easy_install.txt 29 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925
Python API for egg and script installation
==========================================

The easy_install module provides some functions to provide support for
egg and script installation.  It provides functionality at the python
level that is similar to easy_install, with a few exceptions:

- By default, we look for new packages *and* the packages that
  they depend on.  This is somewhat like (and uses) the --upgrade
  option of easy_install, except that we also upgrade required
  packages. 

- If the highest-revision package satisfying a specification is
  already present, then we don't try to get another one.  This saves a
  lot of search time in the common case that packages are pegged to
  specific versions.

- If there is a develop egg that satisfies a requirement, we don't
  look for additional distributions.  We always give preference to
  develop eggs.

- Distutils options for building extensions can be passed.

Distribution installation
-------------------------

The easy_install module provides a function, install, for installing one
or more packages and their dependencies.  The install function takes 2
positional arguments:

- An iterable of setuptools requirement strings for the distributions
  to be installed, and

- A destination directory to install to and to satisfy requirements
  from.  The destination directory can be None, in which case, no new
  distributions are downloaded and there will be an error if the
  needed distributions can't be found amoung those already installed.

It supports a number of optional keyword arguments:

find-links
   A sequence of URLs, file names, or directories to look for
   links to distributions.

index
   The URL of an index server, or almost any other valid URL. :)

   If not specified, the Python Package Index,
   http://cheeseshop.python.org/pypi, is used.  You can specify an
   alternate index with this option.  If you use the links option and
   if the links point to the needed distributions, then the index can
   be anything and will be largely ignored.  In the examples, here,
   we'll just point to an empty directory on our link server.  This 
   will make our examples run a little bit faster.

executable
   A path to a Python executable.  Distributions will ne installed
   using this executable and will be for the matching Python version.

path
   A list of additional directories to search for locally-installed
   distributions.

always_unzip
   A flag indicating that newly-downloaded distributions should be
   directories even if they could be installed as zip files.

working_set
   An exsiting working set to be augmented with additional
   distributions, if necessary to satisfy requirements.  This allows
   you to call install multiple times, if necessary, to gather
   multiple sets of requirements.

newest
   A boolian value indicating whether to search for new distributions
   when already-installed distributions meet the requirement.  When
   this is true, the default, and when the destination directory is
   not None, then the install function will search for the newest
   distributions that satisfy the requirements.

versions
   A dictionary mapping project names to version numbers to be used
   when selecting distributions.  This can be used to specify a set of
   distribution versions independent of other requirements.

The install method returns a working set containing the distributions
needed to meet the given requirements.

We have a link server that has a number of eggs:

    >>> print get(link_server),
    <html><body>
    <a href="demo-0.1-py2.4.egg">demo-0.1-py2.4.egg</a><br>
    <a href="demo-0.2-py2.4.egg">demo-0.2-py2.4.egg</a><br>
    <a href="demo-0.3-py2.4.egg">demo-0.3-py2.4.egg</a><br>
    <a href="demoneeded-1.0.zip">demoneeded-1.0.zip</a><br>
    <a href="demoneeded-1.1.zip">demoneeded-1.1.zip</a><br>
    <a href="extdemo-1.4.zip">extdemo-1.4.zip</a><br>
    <a href="index/">index/</a><br>
    <a href="other-1.0-py2.4.egg">other-1.0-py2.4.egg</a><br>
    </body></html>

Let's make a directory and install the demo egg to it, using the demo:

    >>> 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/')
    
We requested version 0.2 of the demo distribution to be installed into
the destination server.  We specified that we should search for links
on the link server and that we should use the (empty) link server 
index directory as a package index.

The working set contains the distributions we retrieved.

    >>> for dist in ws:
    ...     print dist
    demo 0.2
    demoneeded 1.1

And the actual eggs were added to the eggs directory.

    >>> ls(dest)
    -  demo-0.2-py2.4.egg
    -  demoneeded-1.1-py2.4.egg

If we remove the version restriction on demo, but specify a false
value for newest, no new didstributions will be installed:

    >>> ws = zc.buildout.easy_install.install(
    ...     ['demo'], dest, links=[link_server], index=link_server+'index/',
    ...     newest=False)
    >>> ls(dest)
    -  demo-0.2-py2.4.egg
    -  demoneeded-1.1-py2.4.egg

If we leave off the newst option, we'll get an update for demo:

    >>> ws = zc.buildout.easy_install.install(
    ...     ['demo'], dest, links=[link_server], index=link_server+'index/')
    >>> ls(dest)
    -  demo-0.2-py2.4.egg
    -  demo-0.3-py2.4.egg
    -  demoneeded-1.1-py2.4.egg

We can supply additional distributions.  We can also supply
specifications for distributions that would normally be found via
dependencies.  We might do this to specify a sprcific version.

    >>> ws = zc.buildout.easy_install.install(
    ...     ['demo', 'other', 'demoneeded==1.0'], dest,
    ...     links=[link_server], index=link_server+'index/')

    >>> for dist in ws:
    ...     print dist
    demo 0.3
    other 1.0
    demoneeded 1.0

    >>> ls(dest)
    -  demo-0.2-py2.4.egg
    -  demo-0.3-py2.4.egg
    -  demoneeded-1.0-py2.4.egg
    -  demoneeded-1.1-py2.4.egg
    d  other-1.0-py2.4.egg

We can request that eggs be unzipped even if they are zip safe.  This
can be useful when debugging.

    >>> rmdir(dest)
    >>> dest = tmpdir('sample-install')
    >>> ws = zc.buildout.easy_install.install(
    ...     ['demo'], dest, links=[link_server], index=link_server+'index/',
    ...     always_unzip=True)

    >>> ls(dest)
    d  demo-0.3-py2.4.egg
    d  demoneeded-1.1-py2.4.egg

    
    >>> rmdir(dest)
    >>> dest = tmpdir('sample-install')
    >>> ws = zc.buildout.easy_install.install(
    ...     ['demo'], dest, links=[link_server], index=link_server+'index/',
    ...     always_unzip=True)

    >>> ls(dest)
    d  demo-0.3-py2.4.egg
    d  demoneeded-1.1-py2.4.egg

Specifying version information indepenent of requirements
---------------------------------------------------------

Sometimes it's useful to specify version information indepenent of
normal requirements specifications.  For example, a buildout may need
to lock down a set of versions, without having to put put version
numbers in setup files or part definitions.  If a dictionary is passed
to the install function, mapping project names to version numbers,
then the versions numbers will be used.

    >>> ws = zc.buildout.easy_install.install(
    ...     ['demo'], dest, links=[link_server], index=link_server+'index/',
    ...     versions = dict(demo='0.2', demoneeded='1.0'))
    >>> [d.version for d in ws]
    ['0.2', '1.0']

In this example, we specified a version for demoneeded, even though we
didn't define a requirement for it.  The versions specified apply to
depenencies as well as the specified requirements.

If we specify a version that's incompatible with a requirement, then
we'll get an error:

    >>> from zope.testing.loggingsupport import InstalledHandler
    >>> handler = InstalledHandler('zc.buildout.easy_install')
    >>> import logging
    >>> logging.getLogger('zc.buildout.easy_install').propagate = False

    >>> ws = zc.buildout.easy_install.install(
    ...     ['demo >0.2'], dest, links=[link_server],
    ...     index=link_server+'index/',
    ...     versions = dict(demo='0.2', demoneeded='1.0'))
    Traceback (most recent call last):
    ...
    IncompatibleVersionError: Bad version 0.2

    >>> print handler
    zc.buildout.easy_install DEBUG
      Installing ['demo >0.2']
    zc.buildout.easy_install ERROR
      The version, 0.2, is not consistent with the requirement, demo>0.2

    >>> handler.clear()

If no versions are specified, a debugging message will be output 
reporting that a version was picked automatically:

    >>> ws = zc.buildout.easy_install.install(
    ...     ['demo'], dest, links=[link_server], index=link_server+'index/',
    ...     )

    >>> print handler
    zc.buildout.easy_install DEBUG
      Installing ['demo']
    zc.buildout.easy_install DEBUG
      We have the best distribution that satisfies
    demo
    zc.buildout.easy_install.picked DEBUG
      demo = 0.3
    zc.buildout.easy_install DEBUG
      Getting required demoneeded
    zc.buildout.easy_install DEBUG
      We have the best distribution that satisfies
    demoneeded
    zc.buildout.easy_install.picked DEBUG
      demoneeded = 1.1

    >>> handler.uninstall()
    >>> logging.getLogger('zc.buildout.easy_install').propagate = True

The function default_versions can be used to get and set default
version information to be used when no version information is passes.
If called with an argument, it sets the default versions:

    >>> zc.buildout.easy_install.default_versions(dict(demoneeded='1'))
    {}

It always returns the previous default versions.  If called without an
argument, it simply returns the default versions without changing
them:

    >>> zc.buildout.easy_install.default_versions()
    {'demoneeded': '1'}

So with the default versions set, we'll get the requested version even
if the versions option isn't used:

    >>> ws = zc.buildout.easy_install.install(
    ...     ['demo'], dest, links=[link_server], index=link_server+'index/',
    ...     )

    >>> [d.version for d in ws]
    ['0.3', '1.0']

Of course, we can unset the default versions by passing an empty
dictionary:

    >>> zc.buildout.easy_install.default_versions({})
    {'demoneeded': '1'}

    >>> ws = zc.buildout.easy_install.install(
    ...     ['demo'], dest, links=[link_server], index=link_server+'index/',
    ...     )

    >>> [d.version for d in ws]
    ['0.3', '1.1']
    

Script generation
-----------------

The easy_install module provides support for creating scripts from
eggs.  It provides a function similar to setuptools except that it
provides facilities for baking a script's path into the script.  This
has two advantages:

- The eggs to be used by a script are not chosen at run time, making
  startup faster and, more importantly, deterministic.

- The script doesn't have to import pkg_resources because the logic
  that pkg_resources would execute at run time is executed at
  script-creation time.

The scripts method can be used to generate scripts. Let's create a
destination directory for it to place them in:

    >>> import tempfile
    >>> bin = tmpdir('bin')

Now, we'll use the scripts method to generate scripts in this directory
from the demo egg:

    >>> import sys
    >>> scripts = zc.buildout.easy_install.scripts(
    ...     ['demo'], ws, sys.executable, bin)

the four arguments we passed were:

1. A sequence of distribution requirements.  These are of the same
   form as setuptools requirements.  Here we passed a single
   requirement, for the version 0.1 demo distribution.

2. A working set,

3. The Python executable to use, and 

3. The destination directory.

The bin directory now contains a generated script:

    >>> ls(bin)
    -  demo

The return value is a list of the scripts generated:
    
    >>> import os, sys
    >>> if sys.platform == 'win32':
    ...     scripts == [os.path.join(bin, 'demo.exe'), 
    ...                 os.path.join(bin, 'demo-script.py')]
    ... else:
    ...     scripts == [os.path.join(bin, 'demo')]
    True

Note that in Windows, 2 files are generated for each script.  A script
file, ending in '-script.py', and an exe file that allows the script
to be invoked directly without having to specify the Python
interpreter and without having to provide a '.py' suffix.

The demo script run the entry point defined in the demo egg:

    >>> cat(bin, 'demo') # doctest: +NORMALIZE_WHITESPACE
    #!/usr/local/bin/python2.4
    <BLANKLINE>
    import sys
    sys.path[0:0] = [
      '/sample-install/demo-0.3-py2.4.egg',
      '/sample-install/demoneeded-1.1-py2.4.egg',
      ]
    <BLANKLINE>
    import eggrecipedemo
    <BLANKLINE>
    if __name__ == '__main__':
        eggrecipedemo.main()

Some things to note:

- The demo and demoneeded eggs are added to the beginning of sys.path.

- The module for the script entry point is imported and the entry
  point, in this case, 'main', is run.

Rather than requirement strings, you can pass tuples containing 3
strings:

  - A script name,

  - A module,

  - An attribute expression for an entry point within the module.

For example, we could have passed antry point information directly
rather than passing a requirement:

    >>> scripts = zc.buildout.easy_install.scripts(
    ...     [('demo', 'eggrecipedemo', 'main')],
    ...     ws, sys.executable, bin)

    >>> cat(bin, 'demo') # doctest: +NORMALIZE_WHITESPACE
    #!/usr/local/bin/python2.4
    <BLANKLINE>
    import sys
    sys.path[0:0] = [
      '/sample-install/demo-0.3-py2.4.egg',
      '/sample-install/demoneeded-1.1-py2.4.egg',
      ]
    <BLANKLINE>
    import eggrecipedemo
    <BLANKLINE>
    if __name__ == '__main__':
        eggrecipedemo.main()

Passing entry-point information directly is handy when using eggs (or
distributions) that don't declare their entry points, such as
distributions that aren't based on setuptools.

The interpreter keyword argument can be used to generate a script that can
be used to invoke the Python interactive interpreter with the path set
based on the working set.  This generated script can also be used to
run other scripts with the path set on the working set:

    >>> scripts = zc.buildout.easy_install.scripts(
    ...     ['demo'], ws, sys.executable, bin, interpreter='py')


    >>> ls(bin)
    -  demo
    -  py

    >>> if sys.platform == 'win32':
    ...     scripts == [os.path.join(bin, 'demo.exe'),
    ...                 os.path.join(bin, 'demo-script.py'),
    ...                 os.path.join(bin, 'py.exe'),
    ...                 os.path.join(bin, 'py-script.py')]
    ... else:
    ...     scripts == [os.path.join(bin, 'demo'),
    ...                 os.path.join(bin, 'py')]
    True

The py script simply runs the Python interactive interpreter with
the path set:

    >>> cat(bin, 'py') # doctest: +NORMALIZE_WHITESPACE
    #!/usr/local/bin/python2.4
    import sys
    <BLANKLINE>
    sys.path[0:0] = [
      '/sample-install/demo-0.3-py2.4.egg',
      '/sample-install/demoneeded-1.1-py2.4.egg',
      ]
    <BLANKLINE>
    _interactive = True
    if len(sys.argv) > 1:
        import getopt
        _options, _args = getopt.getopt(sys.argv[1:], 'ic:')
        _interactive = False
        for (_opt, _val) in _options:
            if _opt == '-i':
                _interactive = True
            elif _opt == '-c':
                exec _val
    <BLANKLINE>
        if _args:
            sys.argv[:] = _args
            execfile(sys.argv[0])
    <BLANKLINE>
    if _interactive:
        import code
        code.interact(banner="", local=globals())

If invoked with a script name and arguments, it will run that script, instead.

An additional argumnet can be passed to define which scripts to install
and to provide script names. The argument is a dictionary mapping
original script names to new script names.

    >>> bin = tmpdir('bin2')
    >>> scripts = zc.buildout.easy_install.scripts(
    ...    ['demo'], ws, sys.executable, bin, dict(demo='run'))

    >>> if sys.platform == 'win32':
    ...     scripts == [os.path.join(bin, 'run.exe'),
    ...                 os.path.join(bin, 'run-script.py')]
    ... else:
    ...     scripts == [os.path.join(bin, 'run')]
    True
    >>> ls(bin)
    -  run

    >>> print system(os.path.join(bin, 'run')),
    3 1

Including extra paths in scripts
--------------------------------

We can pass a keyword argument, extra paths, to caue additional paths
to be included in the a generated script:

    >>> scripts = zc.buildout.easy_install.scripts(
    ...    ['demo'], ws, sys.executable, bin, dict(demo='run'),
    ...    extra_paths=['/foo/bar'])

    >>> cat(bin, 'run') # doctest: +NORMALIZE_WHITESPACE
    #!/usr/local/bin/python2.4
    <BLANKLINE>
    import sys
    sys.path[0:0] = [
      '/sample-install/demo-0.3-py2.4.egg',
      '/sample-install/demoneeded-1.1-py2.4.egg',
      '/foo/bar',
      ]
    <BLANKLINE>
    import eggrecipedemo
    <BLANKLINE>
    if __name__ == '__main__':
        eggrecipedemo.main()

Providing script arguments
--------------------------

An "argument" keyword argument can be used to pass arguments to an
entry point.  The value passed is a source string to be placed between the
parentheses in the call:

    >>> scripts = zc.buildout.easy_install.scripts(
    ...    ['demo'], ws, sys.executable, bin, dict(demo='run'),
    ...    arguments='1, 2')

    >>> cat(bin, 'run') # doctest: +NORMALIZE_WHITESPACE
    #!/usr/local/bin/python2.4
    import sys
    sys.path[0:0] = [
      '/sample-install/demo-0.3-py2.4.egg',
      '/sample-install/demoneeded-1.1-py2.4.egg',
      ]
    <BLANKLINE>
    import eggrecipedemo
    <BLANKLINE>
    if __name__ == '__main__':
        eggrecipedemo.main(1, 2)

Passing initialization code
---------------------------

You can also pass script initialization code:

    >>> scripts = zc.buildout.easy_install.scripts(
    ...    ['demo'], ws, sys.executable, bin, dict(demo='run'),
    ...    arguments='1, 2', 
    ...    initialization='import os\nos.chdir("foo")')

    >>> cat(bin, 'run') # doctest: +NORMALIZE_WHITESPACE
    #!/usr/local/bin/python2.4
    import sys
    sys.path[0:0] = [
      '/sample-install/demo-0.3-py2.4.egg',
      '/sample-install/demoneeded-1.1-py2.4.egg',
      ]
    <BLANKLINE>
    import os
    os.chdir("foo")
    <BLANKLINE>
    import eggrecipedemo
    <BLANKLINE>
    if __name__ == '__main__':
        eggrecipedemo.main(1, 2)


Handling custom build options for extensions provided in source distributions
-----------------------------------------------------------------------------

Sometimes, we need to control how extension modules are built.  The
build function provides this level of control.  It takes a single
package specification, downloads a source distribution, and builds it
with specified custom build options.

The build function takes 3 positional arguments:

spec
   A package specification for a source distribution

dest
   A destination directory

build_ext
   A dictionary of options to be passed to the distutils build_ext
   command when building extensions.

It supports a number of optional keyword arguments:

links
   a sequence of URLs, file names, or directories to look for
   links to distributions,

index
   The URL of an index server, or almost any other valid URL. :)

   If not specified, the Python Package Index,
   http://cheeseshop.python.org/pypi, is used.  You can specify an
   alternate index with this option.  If you use the links option and
   if the links point to the needed distributions, then the index can
   be anything and will be largely ignored.  In the examples, here,
   we'll just point to an empty directory on our link server.  This 
   will make our examples run a little bit faster.

executable
   A path to a Python executable.  Distributions will ne installed
   using this executable and will be for the matching Python version.

path
   A list of additional directories to search for locally-installed
   distributions.

newest
   A boolian value indicating whether to search for new distributions
   when already-installed distributions meet the requirement.  When
   this is true, the default, and when the destination directory is
   not None, then the install function will search for the newest
   distributions that satisfy the requirements.

versions
   A dictionary mapping project names to version numbers to be used
   when selecting distributions.  This can be used to specify a set of
   distribution versions independent of other requirements.


Our link server included a source distribution that includes a simple
extension, extdemo.c::

  #include <Python.h>
  #include <extdemo.h>

  static PyMethodDef methods[] = {};

  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
  }

The extension depends on a system-dependent include file, extdemo.h,
that defines a constant, EXTDEMO, that is exposed by the extension.

We'll add an include directory to our sample buildout and add the
needed include file to it:

    >>> mkdir('include')
    >>> write('include', 'extdemo.h',
    ... """
    ... #define EXTDEMO 42
    ... """)

Now, we can use the build function to create an egg from the source
distribution:

    >>> zc.buildout.easy_install.build(
    ...   'extdemo', dest, 
    ...   {'include-dirs': os.path.join(sample_buildout, 'include')},
    ...   links=[link_server], index=link_server+'index/')
    ['/sample-install/extdemo-1.4-py2.4-unix-i686.egg']

The function returns the list of eggs 

Now if we look in our destination directory, we see we have an extdemo egg:

    >>> ls(dest)
    -  demo-0.2-py2.4.egg
    d  demo-0.3-py2.4.egg
    -  demoneeded-1.0-py2.4.egg
    d  demoneeded-1.1-py2.4.egg
    d  extdemo-1.4-py2.4-unix-i686.egg

Let's update our link server with a new version of extdemo:

    >>> update_extdemo()
    >>> print get(link_server),
    <html><body>
    <a href="demo-0.1-py2.4.egg">demo-0.1-py2.4.egg</a><br>
    <a href="demo-0.2-py2.4.egg">demo-0.2-py2.4.egg</a><br>
    <a href="demo-0.3-py2.4.egg">demo-0.3-py2.4.egg</a><br>
    <a href="demoneeded-1.0.zip">demoneeded-1.0.zip</a><br>
    <a href="demoneeded-1.1.zip">demoneeded-1.1.zip</a><br>
    <a href="extdemo-1.4.zip">extdemo-1.4.zip</a><br>
    <a href="extdemo-1.5.zip">extdemo-1.5.zip</a><br>
    <a href="index/">index/</a><br>
    <a href="other-1.0-py2.4.egg">other-1.0-py2.4.egg</a><br>
    </body></html>

The easy_install caches information about servers to reduce network
access. To see the update, we have to call the clear_index_cache
function to clear the index cache:

    >>> zc.buildout.easy_install.clear_index_cache()

If we run build with newest set to False, we won't get an update:

    >>> zc.buildout.easy_install.build(
    ...   'extdemo', 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']

    >>> ls(dest)
    -  demo-0.2-py2.4.egg
    d  demo-0.3-py2.4.egg
    -  demoneeded-1.0-py2.4.egg
    d  demoneeded-1.1-py2.4.egg
    d  extdemo-1.4-py2.4-unix-i686.egg

But if we run it with the default True setting for newest, then we'll
get an updated egg:

    >>> zc.buildout.easy_install.build(
    ...   'extdemo', dest, 
    ...   {'include-dirs': os.path.join(sample_buildout, 'include')},
    ...   links=[link_server], index=link_server+'index/')
    ['/sample-install/extdemo-1.5-py2.4-unix-i686.egg']

    >>> ls(dest)
    -  demo-0.2-py2.4.egg
    d  demo-0.3-py2.4.egg
    -  demoneeded-1.0-py2.4.egg
    d  demoneeded-1.1-py2.4.egg
    d  extdemo-1.4-py2.4-unix-i686.egg
    d  extdemo-1.5-py2.4-unix-i686.egg

The versions option also influences the versions used.  For example,
if we specify a version for extdemo, then that will be used, even
though it isn't the newest.  Let's clean out the destimation directory
first:

    >>> import os
    >>> for name in os.listdir(dest):
    ...     remove(dest, name)

    >>> zc.buildout.easy_install.build(
    ...   'extdemo', dest, 
    ...   {'include-dirs': os.path.join(sample_buildout, 'include')},
    ...   links=[link_server], index=link_server+'index/',
    ...   versions=dict(extdemo='1.4'))
    ['/sample-install/extdemo-1.4-py2.4-unix-i686.egg']

    >>> ls(dest)
    d  extdemo-1.4-py2.4-unix-i686.egg

Handling custom build options for extensions in develop eggs
------------------------------------------------------------

The develop function is similar to the build function, except that,
rather than building an egg from a source directory containing a
setup.py script.  

The develop function takes 2 positional arguments:

setup
   The path to a setup script, typically named "setup.py", or a
   directory containing a setup.py script.

dest
   The directory to install the egg link to

It supports some optional keyword argument:

build_ext
   A dictionary of options to be passed to the distutils build_ext
   command when building extensions.

executable
   A path to a Python executable.  Distributions will ne installed
   using this executable and will be for the matching Python version.

We have a local directory containing the extdemo source:

    >>> ls(extdemo)
    -  MANIFEST
    -  MANIFEST.in
    -  README
    -  extdemo.c
    -  setup.py

Now, we can use the develop function to create a develop egg from the source
distribution:

    >>> zc.buildout.easy_install.develop(
    ...   extdemo, dest, 
    ...   {'include-dirs': os.path.join(sample_buildout, 'include')})
    '/sample-install/extdemo.egg-link'

The name of the egg link created is returned.

Now if we look in our destination directory, we see we have an extdemo
egg link:

    >>> ls(dest)
    d  extdemo-1.4-py2.4-unix-i686.egg
    -  extdemo.egg-link

And that the source directory contains the compiled extension:

    >>> ls(extdemo)
    -  MANIFEST
    -  MANIFEST.in
    -  README
    d  build
    -  extdemo.c
    d  extdemo.egg-info
    -  extdemo.so
    -  setup.py

Download cache
--------------

Normally, when distributions are installed, if any processing is
needed, they are downloaded from the internet to a temporary directory
and then installed from there.  A download cache can be used to avoid
the download step.  This can be useful to reduce network access and to
create source distributions of an entire buildout.

A download cache is specified by calling the download_cache
function.  The function always returns the previous setting. If no
argument is passed, then the setting is unchanged.  Is an argument is
passed, the download cache is set to the given path, which must point
to an existing directory.  Passing None clears the cache setting.

To see this work, we'll create a directory and set it as the cache
directory:

    >>> cache = tmpdir('cache')
    >>> zc.buildout.easy_install.download_cache(cache)

We'll recreate out destination directory:

    >>> remove(dest)
    >>> dest = tmpdir('sample-install')

We'd like to see what is being fetched from the server, so we'll
enable server logging:
   
    >>> get(link_server+'enable_server_logging')
    GET 200 /enable_server_logging
    ''

Now, if we install demo, and extdemo:

    >>> ws = zc.buildout.easy_install.install(
    ...     ['demo==0.2'], dest,
    ...     links=[link_server], index=link_server+'index/', 
    ...     always_unzip=True)
    GET 200 /
    GET 404 /index/demo/
    GET 200 /index/
    GET 200 /demo-0.2-py2.4.egg
    GET 404 /index/demoneeded/
    GET 200 /demoneeded-1.1.zip
    GET 404 /index/setuptools/

    >>> zc.buildout.easy_install.build(
    ...   'extdemo', dest, 
    ...   {'include-dirs': os.path.join(sample_buildout, 'include')},
    ...   links=[link_server], index=link_server+'index/')
    GET 404 /index/extdemo/
    GET 200 /extdemo-1.5.zip
    ['/sample-install/extdemo-1.5-py2.4-linux-i686.egg']

Not only will we get eggs in our destination directory:

    >>> ls(dest)
    d  demo-0.2-py2.4.egg
    d  demoneeded-1.1-py2.4.egg
    d  extdemo-1.5-py2.4-linux-i686.egg

But we'll get distributions in the cache directory:

    >>> ls(cache)
    -  demo-0.2-py2.4.egg
    -  demoneeded-1.1.zip
    -  extdemo-1.5.zip

The cache directory contains uninstalled distributions, such as zipped
eggs or source distributions.  

Let's recreate our destination directory and clear the index cache:

    >>> remove(dest)
    >>> dest = tmpdir('sample-install')
    >>> zc.buildout.easy_install.clear_index_cache()

Now when we install the distributions:

    >>> ws = zc.buildout.easy_install.install(
    ...     ['demo==0.2'], dest,
    ...     links=[link_server], index=link_server+'index/', 
    ...     always_unzip=True)
    GET 200 /
    GET 404 /index/demo/
    GET 200 /index/
    GET 404 /index/demoneeded/
    GET 404 /index/setuptools/

    >>> zc.buildout.easy_install.build(
    ...   'extdemo', dest, 
    ...   {'include-dirs': os.path.join(sample_buildout, 'include')},
    ...   links=[link_server], index=link_server+'index/')
    GET 404 /index/extdemo/
    ['/sample-install/extdemo-1.5-py2.4-linux-i686.egg']

    >>> ls(dest)
    d  demo-0.2-py2.4.egg
    d  demoneeded-1.1-py2.4.egg
    d  extdemo-1.5-py2.4-linux-i686.egg

Note that we didn't download the distributions from the link server.

.. Disable the download cache:

    >>> zc.buildout.easy_install.download_cache(None)
    '/cache'