[Checkins] SVN: zc.recipe.macro/ Initial release checkin of zc.recipe.macro.

Aaron Lehmann aaron at zope.com
Thu Jul 10 22:55:17 EDT 2008


Log message for revision 88233:
  Initial release checkin of zc.recipe.macro.
  
  

Changed:
  _U  zc.recipe.macro/
  A   zc.recipe.macro/CHANGES.txt
  A   zc.recipe.macro/buildout.cfg
  A   zc.recipe.macro/setup.py
  A   zc.recipe.macro/src/
  A   zc.recipe.macro/src/zc/
  A   zc.recipe.macro/src/zc/__init__.py
  A   zc.recipe.macro/src/zc/recipe/
  A   zc.recipe.macro/src/zc/recipe/__init__.py
  A   zc.recipe.macro/src/zc/recipe/macro/
  A   zc.recipe.macro/src/zc/recipe/macro/QUICKSTART.txt
  A   zc.recipe.macro/src/zc/recipe/macro/README.txt
  A   zc.recipe.macro/src/zc/recipe/macro/__init__.py
  A   zc.recipe.macro/src/zc/recipe/macro/recipe.py
  A   zc.recipe.macro/src/zc/recipe/macro/tests.py

-=-

Property changes on: zc.recipe.macro
___________________________________________________________________
Name: svn:ignore
   + bin
develop-eggs
dist
eggs
parts
uuid.txt
.installed.cfg

Name: svn:externals
   + bootstrap svn://svn.zope.org/repos/main/zc.buildout/trunk/bootstrap


Added: zc.recipe.macro/CHANGES.txt
===================================================================
--- zc.recipe.macro/CHANGES.txt	                        (rev 0)
+++ zc.recipe.macro/CHANGES.txt	2008-07-11 02:55:17 UTC (rev 88233)
@@ -0,0 +1,7 @@
+CHANGES
+=======
+
+1.2.0 (07-10-2008) 
+-------------------
+
+First release


Property changes on: zc.recipe.macro/CHANGES.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: zc.recipe.macro/buildout.cfg
===================================================================
--- zc.recipe.macro/buildout.cfg	                        (rev 0)
+++ zc.recipe.macro/buildout.cfg	2008-07-11 02:55:17 UTC (rev 88233)
@@ -0,0 +1,16 @@
+[buildout]
+develop = .
+parts = test
+versions = versions
+
+[versions]
+setuptools = 0.6c8
+zc.recipe.testrunner = 1.0.0
+zc.recipe.egg = 1.0.0
+zc.buildout = 1.0.0
+zope.testing = 3.5.0
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = zc.recipe.macro
+defaults = ["-1"]

Added: zc.recipe.macro/setup.py
===================================================================
--- zc.recipe.macro/setup.py	                        (rev 0)
+++ zc.recipe.macro/setup.py	2008-07-11 02:55:17 UTC (rev 88233)
@@ -0,0 +1,114 @@
+##############################################################################
+#
+# Copyright (c) 2006-2008 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+import os
+from setuptools import setup, find_packages
+
+# generic helpers primarily for the long_description
+try:
+    import docutils
+except ImportError:
+    def validateReST(text):
+        return ''
+else:
+    import docutils.utils
+    import docutils.parsers.rst
+    import StringIO
+    def validateReST(text):
+        doc = docutils.utils.new_document('validator')
+        # our desired settings
+        doc.reporter.halt_level = 5
+        doc.reporter.report_level = 1
+        stream = doc.reporter.stream = StringIO.StringIO()
+        # docutils buglets (?)
+        doc.settings.tab_width = 2
+        doc.settings.pep_references = doc.settings.rfc_references = False
+        doc.settings.trim_footnote_reference_space = None
+        # and we're off...
+        parser = docutils.parsers.rst.Parser()
+        parser.parse(text, doc)
+        return stream.getvalue()
+
+def text(*args, **kwargs):
+    # note: distutils explicitly disallows unicode for setup values :-/
+    # http://docs.python.org/dist/meta-data.html
+    tmp = []
+    for a in args:
+        if a.endswith('.txt'):
+            f = open(os.path.join(*a.split('/')))
+            tmp.append(f.read())
+            f.close()
+            tmp.append('\n\n')
+        else:
+            tmp.append(a)
+    if len(tmp) == 1:
+        res = tmp[0]
+    else:
+        res = ''.join(tmp)
+    out = kwargs.get('out')
+    if out is True:
+        out = 'TEST_THIS_REST_BEFORE_REGISTERING.txt'
+    if out:
+        f = open(out, 'w')
+        f.write(res)
+        f.close()
+        report = validateReST(res)
+        if report:
+            print report
+            raise ValueError('ReST validation error')
+    return res
+# end helpers; below this line should be code custom to this package
+
+
+
+ENTRY_POINTS = """
+[zc.buildout]
+default = zc.recipe.macro:Macro
+test = zc.recipe.macro:Test
+empty = zc.recipe.macro:Empty
+"""
+
+
+setuptools.setup(
+    name="zc.recipe.macro",
+    version="1.2.0",
+    description="Macro-recipe for buildout.",
+    long_description=text(
+        'src/zc/recipe/macro/QUICKSTART.txt',
+        "=======\nChanges\n=======\n\n",
+        'CHANGES.txt',
+        out=True),
+    keywords="development build macro",
+    classifiers = [
+       'Framework :: Buildout',
+       'Intended Audience :: Developers',
+       'License :: OSI Approved :: Zope Public License',
+       'Topic :: Software Development :: Build Tools',
+       'Topic :: Software Development :: Libraries :: Python Modules',
+       ],
+    author="Aaron Lehmann",
+    author_email="aaron at zope.com",
+    license="ZPL 2.1",
+
+    package_dir={"": "src"},
+    packages=setuptools.find_packages("src"),
+    namespace_packages=["zc", "zc.recipe"],
+    install_requires=[
+        "setuptools",
+        "zc.recipe.testrunner",
+        "zope.testing",
+        ],
+    include_package_data=True,
+    zip_safe=False,
+    entry_points=ENTRY_POINTS,
+    )


Property changes on: zc.recipe.macro/setup.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: zc.recipe.macro/src/zc/__init__.py
===================================================================
--- zc.recipe.macro/src/zc/__init__.py	                        (rev 0)
+++ zc.recipe.macro/src/zc/__init__.py	2008-07-11 02:55:17 UTC (rev 88233)
@@ -0,0 +1,10 @@
+# This directory is a Python namespace package.
+try:
+    import pkg_resources
+except ImportError:
+    import pkgutil
+    __path__ = pkgutil.extend_path(__path__, __name__)
+    del pkgutil
+else:
+    pkg_resources.declare_namespace(__name__)
+    del pkg_resources


Property changes on: zc.recipe.macro/src/zc/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: zc.recipe.macro/src/zc/recipe/__init__.py
===================================================================
--- zc.recipe.macro/src/zc/recipe/__init__.py	                        (rev 0)
+++ zc.recipe.macro/src/zc/recipe/__init__.py	2008-07-11 02:55:17 UTC (rev 88233)
@@ -0,0 +1,10 @@
+# This directory is a Python namespace package.
+try:
+    import pkg_resources
+except ImportError:
+    import pkgutil
+    __path__ = pkgutil.extend_path(__path__, __name__)
+    del pkgutil
+else:
+    pkg_resources.declare_namespace(__name__)
+    del pkg_resources


Property changes on: zc.recipe.macro/src/zc/recipe/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: zc.recipe.macro/src/zc/recipe/macro/QUICKSTART.txt
===================================================================
--- zc.recipe.macro/src/zc/recipe/macro/QUICKSTART.txt	                        (rev 0)
+++ zc.recipe.macro/src/zc/recipe/macro/QUICKSTART.txt	2008-07-11 02:55:17 UTC (rev 88233)
@@ -0,0 +1,158 @@
+Macro Quickstart
+================
+
+zc.recipe.macro is a set of recipes allowing sections, or even parts, to be
+created dynamically from a macro section and a parameter section.  This enables
+the buildout to keep its data seperate from its output format.
+
+Basic Use
+---------
+
+In the most basic use of a macro, a section invokes the macro on itself, and
+uses itself as the parameter provider:
+
+    [buildout]
+    parts = hard-rocker
+
+    [rock]
+    question = Why do I rock $${:rocking-style}?
+
+    [hard-rocker]
+    recipe = zc.recipe.macro
+    macro = rock
+    rocking-style = so hard
+
+This will result in::
+
+    [hard-rocker]
+    recipe = zc.recipe.macro:empty
+    question = Why do I rock so hard?
+    rocking-style = so hard
+
+The recipe gets changed to zc.recipe.macro:empty, which is a do nothing recipe,
+because the invoking secion must be a part in order to execute recipes, and
+buildout demands that parts have a recipe, so it couldn't be emptied.
+
+Default Values
+--------------
+
+It is possible to include default values for parameters in a macro, like so::
+
+    [rock]
+    question = Why do I rock $${:rocking-style}?
+    rocking-style = so hard
+
+Creating Parts
+--------------
+
+Of course, there wouldn't much point to this if one could only create sections
+with a dummy recipe.  This is where the result-recipe option comes in::
+
+    [buildout]
+    parts = hard-rocker
+
+    [rock]
+    question = Why do I rock $${:rocking-style}?
+
+    [hard-rocker]
+    recipe = zc.recipe.macro
+    macro = rock
+    result-recipe = zc.recipe.its_still_rock_n_roll_to_me
+    rocking-style = so hard
+
+That will result in::
+
+    [hard-rocker]
+    recipe = zc.recipe.its_still_rock_n_roll_to_me
+    question = Why do I rock so hard?
+    rocking-style = so hard
+
+Targets
+-------
+
+Often, one wants to create multiple new sections.  This is possible with the
+targets option.  This is only useful, however, if one can provide multiple
+sources for parameters.  Fortunately, you can.  Each new section can optionally
+be followed by a colon and the name of a section to use for parameters::
+
+    [buildout]
+    parts = rockers
+
+    [rock]
+    question = Why do I rock $${:rocking-style}?
+
+    [hard-rocker-parameters]
+    rocking-style = so hard
+
+    [socks-rocker-parameters]
+    rocking-style = my socks
+
+    [tired-rocker-parameters]
+    rocking-style = all night
+
+    [rockers]
+    recipe = zc.recipe.macro
+    macro = rock
+    targets =
+        hard-rocker:hard-rocker-parameters
+        socks-rocker:socks-rocker-parameters
+        rocking-style:tired-rocker-parameters
+
+That will generate these rockers::
+
+    [hard-rocker]
+    recipe = zc.recipe.macro:empty
+    question = Why do I rock so hard?
+
+    [socks-rocker]
+    recipe = zc.recipe.macro:empty
+    question = Why do I rock my socks?
+
+    [tired-rocker]
+    recipe = zc.recipe.macro:empty
+    question = Why do I rock all night?
+
+Special Variables
+-----------------
+
+zc.recipe.macro uses __name__ to mean the name of the section the macro is
+being invoked upon.  This allows one to not know the name of particular
+section, but still use it in output::
+
+    [buildout]
+    parts = rockers
+
+    [rock]
+    question = Why does $${:__name__} rock $${:rocking-style}?
+
+    [hard-rocker-parameters]
+    rocking-style = so hard
+
+    [socks-rocker-parameters]
+    rocking-style = my socks
+
+    [tired-rocker-parameters]
+    rocking-style = all night
+
+    [rockers]
+    recipe = zc.recipe.macro
+    macro = rock
+    targets =
+        hard-rocker:hard-rocker-parameters
+        socks-rocker:socks-rocker-parameters
+        rocking-style:tired-rocker-parameters
+
+This will result in rockers like these::
+
+    [hard-rocker]
+    recipe = zc.recipe.macro:empty
+    question = Why does hard-rocker rock so hard?
+
+    [socks-rocker]
+    recipe = zc.recipe.macro:empty
+    question = Why does socks-rocker rock my socks?
+
+    [tired-rocker]
+    recipe = zc.recipe.macro:empty
+    question = Why does tired-rocker rock all night?
+


Property changes on: zc.recipe.macro/src/zc/recipe/macro/QUICKSTART.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: zc.recipe.macro/src/zc/recipe/macro/README.txt
===================================================================
--- zc.recipe.macro/src/zc/recipe/macro/README.txt	                        (rev 0)
+++ zc.recipe.macro/src/zc/recipe/macro/README.txt	2008-07-11 02:55:17 UTC (rev 88233)
@@ -0,0 +1,600 @@
+==========================
+Invoking recipes as macros
+==========================
+
+This recipe provides a macro system for buildout parts; the intent is to avoid
+repitition in buildout configurations.  For buildouts creating several Zope 3
+instances, we've commonly observed that the zope.conf option gets fairly large
+and is repeated for each instance to allow a few substitutions in the middle
+(port numbers and logfile paths are the main culprits).  Pushing the bulk of
+the zope.conf setting to a macro to avoid repeating the syntax, and allowing
+that to refer to settings that are actually specific to instance would
+significantly improve both readability and maintainability of the instace
+configurations.
+
+The macro recipe allows storing the common portions of a part in a section
+that's referred to as a "macro section"; it defines everything common to parts
+that use it, except the recipe option.
+
+Macros are used by parts called "macro invocations".  The invocation uses the
+macro recipe, and identifies the "macro section" using the "macro" option::
+
+    >>> write(sample_buildout, "buildout.cfg",
+    ... """
+    ... [buildout]
+    ... parts = instance0 instance1
+    ... versions = versions
+    ...
+    ... [versions]
+    ... zc.recipe.egg = 1.0.0
+    ... setuptools = 0.6c8
+    ... zc.recipe.testrunner = 1.0.0
+    ... zc.buildout = 1.0.0
+    ... zope.testing = 3.5.0
+    ...
+    ... [instance-macro]
+    ... application = application
+    ... zope.conf =
+    ...     <eventlog>
+    ...         <logfile>
+    ...             path /var/log/myapp/$${:__name__}-z3.log
+    ...         </logfile>
+    ...     </eventlog>
+    ...     <product-config zc.z3monitor>
+    ...         port $${:monitor-port}
+    ...     </product-config>
+    ...
+    ... [instance0]
+    ... recipe = zc.recipe.macro
+    ... result-recipe = zc.recipe.macro:test
+    ... macro = instance-macro
+    ... address = 8080
+    ... monitor-port = 8089
+    ...
+    ... [instance1]
+    ... recipe = zc.recipe.macro
+    ... result-recipe = zc.recipe.macro:test
+    ... macro = instance-macro
+    ... address = 9080
+    ... monitor-port = 9089
+    ... """)
+
+- The ``[buildout]`` section specified two parts, ``instance0`` and
+  ``instance1``.
+
+- These parts in turn specified that they would be using the
+  macro system: ``recipe = zc.recipe.macro``.
+
+- The output of the macro should be used with the ``zc.recipe.macro:test``
+  recipe, as specified by the ``result-recipe`` option.
+
+- This resulting recipe will receive the ``address`` option from the two
+  instance sections.
+
+- It will also receive the (unprocessed) ``application`` option from the
+  ``instance-macro``.
+
+- The recipe will also receive the fully processed result of the
+  ``instance-macro`` ``zope.conf`` option.
+
+  The zope.conf has two substitutions.  They both use the prefix ``$${:``
+  and the suffix ``}``.  This syntax is driven in part by the needs of the
+  ConfigParser library on which zc.buildout relies.
+  
+  * The ``monitor-port`` is replaced with the ``monitor-port`` values from
+    the ``instance0`` and ``instance1`` sections, respectively.
+
+  * The ``__name__`` is a special token that is replaced with the name of
+    the section--in this case the strings "instance0" and "instance1"
+    respectively.
+
+Now we'll run the buildout.
+
+    >>> import os
+    >>> here = os.getcwd()
+    >>> os.chdir(sample_buildout)
+    >>> buildout = os.path.join(sample_buildout, 'bin', 'buildout')
+    >>> print system(buildout)
+    Installing instance0.
+        address: 8080
+        application: application
+        monitor-port: 8089
+        recipe: zc.recipe.macro:test
+        zope.conf: 
+            <eventlog>
+                <logfile>
+                    path /var/log/myapp/instance0-z3.log
+                </logfile>
+            </eventlog>
+            <product-config zc.z3monitor>
+                port 8089
+            </product-config>
+    Installing instance1.
+        address: 9080
+        application: application
+        monitor-port: 9089
+        recipe: zc.recipe.macro:test
+        zope.conf: 
+            <eventlog>
+                <logfile>
+                    path /var/log/myapp/instance1-z3.log
+                </logfile>
+            </eventlog>
+            <product-config zc.z3monitor>
+                port 9089
+            </product-config>
+    <BLANKLINE>
+
+
+This results in parts equivalent to the buildout::
+
+    >>> os.chdir(here)
+    >>> write(sample_buildout, "buildout.cfg",
+    ... """
+    ... [buildout]
+    ... parts = instance0 instance1
+    ... versions = versions
+    ...
+    ... [versions]
+    ... zc.recipe.egg = 1.0.0
+    ... setuptools = 0.6c8
+    ... zc.recipe.testrunner = 1.0.0
+    ... zc.buildout = 1.0.0
+    ... zope.testing = 3.5.0
+    ...
+    ... [instance0]
+    ... recipe = zc.recipe.macro:test
+    ... application = application
+    ... address = 8080
+    ... monitor-port = 8089
+    ... zope.conf =
+    ...     <eventlog>
+    ...         <logfile>
+    ...             path /var/log/myapp/instance0-z3.log
+    ...         </logfile>
+    ...     </eventlog>
+    ...     <product-config zc.z3monitor>
+    ...         port ${instance0:monitor-port}
+    ...     </product-config>
+    ...
+    ... [instance1]
+    ... recipe = zc.recipe.macro:test
+    ... application = application
+    ... address = 9080
+    ... monitor-port = 9089
+    ... zope.conf =
+    ...     <eventlog>
+    ...         <logfile>
+    ...             path /var/log/myapp/instance1-z3.log
+    ...         </logfile>
+    ...     </eventlog>
+    ...     <product-config zc.z3monitor>
+    ...         port ${instance1:monitor-port}
+    ...     </product-config>
+    ... """)
+    >>> os.chdir(sample_buildout)
+    >>> print system(buildout)
+    Updating instance0.
+        address: 8080
+        application: application
+        monitor-port: 8089
+        recipe: zc.recipe.macro:test
+        zope.conf: 
+            <eventlog>
+                <logfile>
+                    path /var/log/myapp/instance0-z3.log
+                </logfile>
+            </eventlog>
+            <product-config zc.z3monitor>
+                port 8089
+            </product-config>
+    Updating instance1.
+        address: 9080
+        application: application
+        monitor-port: 9089
+        recipe: zc.recipe.macro:test
+        zope.conf: 
+            <eventlog>
+                <logfile>
+                    path /var/log/myapp/instance1-z3.log
+                </logfile>
+            </eventlog>
+            <product-config zc.z3monitor>
+                port 9089
+            </product-config>
+    <BLANKLINE>
+
+Note that the options from the invocation are used both to perform
+substitutions and as additional options in the expansion.  The result-recipe
+option is used to determine the recipe used on the resulting part.
+
+Macro invocation without a result-recipe
+----------------------------------------
+
+Sometimes it is good to have a macro that does not result in a part.
+
+    >>> os.chdir(here)
+    >>> write(sample_buildout, "buildout.cfg",
+    ... """
+    ... [buildout]
+    ... parts = instance0 instance1
+    ... versions = versions
+    ...
+    ... [versions]
+    ... zc.recipe.egg = 1.0.0
+    ... setuptools = 0.6c8
+    ... zc.recipe.testrunner = 1.0.0
+    ... zc.buildout = 1.0.0
+    ... zope.testing = 3.5.0
+    ...
+    ... [instance-macro]
+    ... application = application
+    ... zope.conf =
+    ...     <eventlog>
+    ...         <logfile>
+    ...             path /var/log/myapp/$${:__name__}-z3.log
+    ...         </logfile>
+    ...     </eventlog>
+    ...     <product-config zc.z3monitor>
+    ...         port $${:monitor-port}
+    ...     </product-config>
+    ...
+    ... [instance0]
+    ... recipe = zc.recipe.macro
+    ... macro = instance-macro
+    ... address = 8080
+    ... monitor-port = 8089
+    ...
+    ... [instance1]
+    ... recipe = zc.recipe.macro
+    ... macro = instance-macro
+    ... address = 9080
+    ... monitor-port = 9089
+    ... """)
+
+    >>> os.chdir(sample_buildout)
+    >>> buildout = os.path.join(sample_buildout, 'bin', 'buildout')
+    >>> print system(buildout + ' -vv')
+    Installing 'zc.buildout', 'setuptools'.
+    ...
+    <BLANKLINE>
+    Configuration data:
+    [instance-macro]
+    application = application
+    zope.conf = %(__buildout_space_n__)s<eventlog>
+        <logfile>
+        path /var/log/myapp/$${:__name__}-z3.log
+        </logfile>
+        </eventlog>
+        <product-config zc.z3monitor>
+        port $${:monitor-port}
+        </product-config>
+    [instance0]
+    address = 8080
+    application = application
+    monitor-port = 8089
+    recipe = zc.recipe.macro:empty
+    zope.conf = %(__buildout_space_n__)s<eventlog>
+        <logfile>
+        path /var/log/myapp/instance0-z3.log
+        </logfile>
+        </eventlog>
+        <product-config zc.z3monitor>
+        port 8089
+        </product-config>
+    [instance1]
+    address = 9080
+    application = application
+    monitor-port = 9089
+    recipe = zc.recipe.macro:empty
+    zope.conf = %(__buildout_space_n__)s<eventlog>
+        <logfile>
+        path /var/log/myapp/instance1-z3.log
+        </logfile>
+        </eventlog>
+        <product-config zc.z3monitor>
+        port 9089
+        </product-config>
+    [buildout]
+    bin-directory = .../sample-buildout/bin
+    develop-eggs-directory = .../sample-buildout/develop-eggs
+    directory = .../sample-buildout
+    eggs-directory = .../sample-buildout/eggs
+    executable = /Users/aaron/local/bin/python2.4
+    installed = .../sample-buildout/.installed.cfg
+    log-format =
+    log-level = INFO
+    newest = true
+    offline = false
+    parts = instance0 instance1
+    parts-directory = .../sample-buildout/parts
+    python = buildout
+    verbosity = 20
+    versions = versions
+    [versions]
+    setuptools = 0.6c8
+    zc.buildout = 1.0.0
+    zc.recipe.egg = 1.0.0
+    zc.recipe.testrunner = 1.0.0
+    zope.testing = 3.5.0
+    <BLANKLINE>
+    ...
+
+In this case, the zc.recipe.macro recipe is used, with its Empty entry point.
+This entry point doesn't do anything, but we have to have a recipe to use,
+since the macro recipe has declared this to be a part.  The same sort of output
+will come from an empty result-recipe option.
+
+    >>> os.chdir(here)
+    >>> write(sample_buildout, "buildout.cfg",
+    ... """
+    ... [buildout]
+    ... parts = instance0 instance1
+    ... versions = versions
+    ...
+    ... [versions]
+    ... zc.recipe.egg = 1.0.0
+    ... setuptools = 0.6c8
+    ... zc.recipe.testrunner = 1.0.0
+    ... zc.buildout = 1.0.0
+    ... zope.testing = 3.5.0
+    ...
+    ... [instance-macro]
+    ... application = application
+    ... zope.conf =
+    ...     <eventlog>
+    ...         <logfile>
+    ...             path /var/log/myapp/$${:__name__}-z3.log
+    ...         </logfile>
+    ...     </eventlog>
+    ...     <product-config zc.z3monitor>
+    ...         port $${:monitor-port}
+    ...     </product-config>
+    ...
+    ... [instance0]
+    ... recipe = zc.recipe.macro
+    ... result-recipe =
+    ... macro = instance-macro
+    ... address = 8080
+    ... monitor-port = 8089
+    ...
+    ... [instance1]
+    ... recipe = zc.recipe.macro
+    ... result-recipe =
+    ... macro = instance-macro
+    ... address = 9080
+    ... monitor-port = 9089
+    ... """)
+
+    >>> os.chdir(sample_buildout)
+    >>> buildout = os.path.join(sample_buildout, 'bin', 'buildout')
+    >>> print system(buildout + ' -vv')
+    Installing 'zc.buildout', 'setuptools'.
+    ...
+    <BLANKLINE>
+    Configuration data:
+    [instance-macro]
+    application = application
+    zope.conf = %(__buildout_space_n__)s<eventlog>
+        <logfile>
+        path /var/log/myapp/$${:__name__}-z3.log
+        </logfile>
+        </eventlog>
+        <product-config zc.z3monitor>
+        port $${:monitor-port}
+        </product-config>
+    [instance0]
+    address = 8080
+    application = application
+    monitor-port = 8089
+    recipe = zc.recipe.macro:empty
+    zope.conf = %(__buildout_space_n__)s<eventlog>
+        <logfile>
+        path /var/log/myapp/instance0-z3.log
+        </logfile>
+        </eventlog>
+        <product-config zc.z3monitor>
+        port 8089
+        </product-config>
+    [instance1]
+    address = 9080
+    application = application
+    monitor-port = 9089
+    recipe = zc.recipe.macro:empty
+    zope.conf = %(__buildout_space_n__)s<eventlog>
+        <logfile>
+        path /var/log/myapp/instance1-z3.log
+        </logfile>
+        </eventlog>
+        <product-config zc.z3monitor>
+        port 9089
+        </product-config>
+    [buildout]
+    bin-directory = .../sample-buildout/bin
+    develop-eggs-directory = .../sample-buildout/develop-eggs
+    directory = .../sample-buildout
+    eggs-directory = .../sample-buildout/eggs
+    executable = /Users/aaron/local/bin/python2.4
+    installed = .../sample-buildout/.installed.cfg
+    log-format =
+    log-level = INFO
+    newest = true
+    offline = false
+    parts = instance0 instance1
+    parts-directory = .../sample-buildout/parts
+    python = buildout
+    verbosity = 20
+    versions = versions
+    [versions]
+    setuptools = 0.6c8
+    zc.buildout = 1.0.0
+    zc.recipe.egg = 1.0.0
+    zc.recipe.testrunner = 1.0.0
+    zope.testing = 3.5.0
+    <BLANKLINE>
+    ...
+
+And of course they are the same as explicitly declaring and empty result.
+
+Targets for Macro Invocation
+----------------------------
+
+Macros don't provide for a seperate scope, by default.  This is often perfectly
+fine, but if we want to make it possible to invoke the same recipe twice, there
+must be a way to target the macro invocation.  The way targetting works is it
+iterates over the names in the targets value, creating a section by that name
+if necesary, and putting the results of the invocation in the new section.  New
+sections are just like any other section, so other sections can refer to their
+options, and they can be used as parts.
+
+    >>> os.chdir(here)
+    >>> write(sample_buildout, "buildout.cfg",
+    ... """
+    ... [buildout]
+    ... parts = invoker0 invoker1
+    ... versions = versions
+    ...
+    ... [versions]
+    ... zc.recipe.egg = 1.0.0
+    ... setuptools = 0.6c8
+    ... zc.recipe.testrunner = 1.0.0
+    ... zc.buildout = 1.0.0
+    ... zope.testing = 3.5.0
+    ...
+    ... [macro]
+    ... output = I was invoked by $${:__name__}
+    ...
+    ... [invoker0]
+    ... recipe = zc.recipe.macro
+    ... macro = macro
+    ... targets = zero
+    ...
+    ... [invoker1]
+    ... recipe = zc.recipe.macro
+    ... macro = macro
+    ... targets = one
+    ... """)
+
+    >>> os.chdir(sample_buildout)
+    >>> buildout = os.path.join(sample_buildout, 'bin', 'buildout')
+    >>> print system(buildout + ' -vv')
+    Installing 'zc.buildout', 'setuptools'.
+    ...
+    <BLANKLINE>
+    Configuration data:
+    [buildout]
+    bin-directory = .../sample-buildout/bin
+    develop-eggs-directory = .../sample-buildout/develop-eggs
+    directory = .../sample-buildout
+    eggs-directory = .../sample-buildout/eggs
+    executable = /Users/aaron/local/bin/python2.4
+    installed = .../sample-buildout/.installed.cfg
+    log-format =
+    log-level = INFO
+    newest = true
+    offline = false
+    parts = invoker0 invoker1
+    parts-directory = .../sample-buildout/parts
+    python = buildout
+    verbosity = 20
+    versions = versions
+    [versions]
+    setuptools = 0.6c8
+    zc.buildout = 1.0.0
+    zc.recipe.egg = 1.0.0
+    zc.recipe.testrunner = 1.0.0
+    zope.testing = 3.5.0
+    [macro]
+    output = I was invoked by $${:__name__}
+    [invoker0]
+    recipe = zc.recipe.macro:empty
+    [invoker1]
+    recipe = zc.recipe.macro:empty
+    [zero]
+    output = I was invoked by zero
+    [one]
+    output = I was invoked by one
+    <BLANKLINE>
+    ...
+
+
+Providing Parameters to Named Macros
+------------------------------------
+
+Another thing that is necesary to being able to use a macro twice in the same
+section is the ability to specify a mapping between the options of the invoker
+and the options in the scope.  Without this, no matter how many times one ran
+the macro, the results would all be the same.  This is done by naming an
+existing section, which will be used as source of values.
+
+    >>> os.chdir(here)
+    >>> write(sample_buildout, "buildout.cfg",
+    ... """
+    ... [buildout]
+    ... parts = invoker0
+    ... versions = versions
+    ...
+    ... [versions]
+    ... zc.recipe.egg = 1.0.0
+    ... setuptools = 0.6c8
+    ... zc.recipe.testrunner = 1.0.0
+    ... zc.buildout = 1.0.0
+    ... zope.testing = 3.5.0
+    ...
+    ... [macro]
+    ... output = I was invoked by $${:name}
+    ... name = $${:__name__}
+    ...
+    ... [invoker0]
+    ... recipe = zc.recipe.macro
+    ... result-recipe =
+    ... macro = macro
+    ... targets = zero:zero-parameters
+    ...
+    ... [zero-parameters]
+    ... name = Otto von Bismark
+    ... """)
+
+    >>> os.chdir(sample_buildout)
+    >>> buildout = os.path.join(sample_buildout, 'bin', 'buildout')
+    >>> print system(buildout + ' -vv')
+    Installing 'zc.buildout', 'setuptools'.
+    ...
+    <BLANKLINE>
+    Configuration data:
+    [zero-parameters]
+    name = Otto von Bismark
+    [versions]
+    setuptools = 0.6c8
+    zc.buildout = 1.0.0
+    zc.recipe.egg = 1.0.0
+    zc.recipe.testrunner = 1.0.0
+    zope.testing = 3.5.0
+    [macro]
+    name = $${:__name__}
+    output = I was invoked by $${:name}
+    [invoker0]
+    recipe = zc.recipe.macro:empty
+    [zero]
+    name = Otto von Bismark
+    output = I was invoked by Otto von Bismark
+    [buildout]
+    bin-directory = .../sample-buildout/bin
+    develop-eggs-directory = .../sample-buildout/develop-eggs
+    directory = .../sample-buildout
+    eggs-directory = .../sample-buildout/eggs
+    executable = /Users/aaron/local/bin/python2.4
+    installed = .../sample-buildout/.installed.cfg
+    log-format =
+    log-level = INFO
+    newest = true
+    offline = false
+    parts = invoker0
+    parts-directory = .../sample-buildout/parts
+    python = buildout
+    verbosity = 20
+    versions = versions
+    <BLANKLINE>
+    ...
+
+


Property changes on: zc.recipe.macro/src/zc/recipe/macro/README.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: zc.recipe.macro/src/zc/recipe/macro/__init__.py
===================================================================
--- zc.recipe.macro/src/zc/recipe/macro/__init__.py	                        (rev 0)
+++ zc.recipe.macro/src/zc/recipe/macro/__init__.py	2008-07-11 02:55:17 UTC (rev 88233)
@@ -0,0 +1,2 @@
+# This directory is a Python package.
+from zc.recipe.macro.recipe import Macro, Test, Empty


Property changes on: zc.recipe.macro/src/zc/recipe/macro/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: zc.recipe.macro/src/zc/recipe/macro/recipe.py
===================================================================
--- zc.recipe.macro/src/zc/recipe/macro/recipe.py	                        (rev 0)
+++ zc.recipe.macro/src/zc/recipe/macro/recipe.py	2008-07-11 02:55:17 UTC (rev 88233)
@@ -0,0 +1,118 @@
+##############################################################################
+#
+# Copyright (c) 2006-2008 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+import re
+import os.path
+import zc.buildout.buildout
+import pprint
+
+
+def evaluate_macro(buildout, name, macro, input, recipe):
+    def replace_match(match):
+        key = match.groups()[0]
+        if key in buildout[input]:
+            ret_val = '${%s:%s}' % (input, key)
+            if key in new_macro:
+                new_macro[key] = ret_val
+        else:
+            ret_val = '${%s:%s}' % (name, key)
+        return ret_val
+    c_re = re.compile(r'\$\$\{:([^}]*)\}')
+    new_macro = dict(macro)
+    for key, value in dict(macro).iteritems():
+        if new_macro.get(key, '') == value:
+            new_macro[key] = c_re.sub(
+                replace_match, value.replace('$${:__name__}', name))
+    if recipe:
+        new_macro['recipe'] = new_macro.get('recipe', recipe)
+    return new_macro
+
+def parse_target(invoker, target):
+    input_section = invoker
+    if ':' in target:
+        target, input_section = target.split(':')
+    return target, input_section
+
+def parse_macro_invocation(invocation):
+    inputs = {}
+    parse = re.match(r'([^:\n]*)(?::([^:{\n]*)(?:{([^}]*)})?)?', invocation, re.M)
+    return tuple(parse.group(x) for x in xrange(1,4))
+
+def Macro(buildout, name, options):
+    del options['recipe']
+    recipe = options.pop('result-recipe', '')
+    macro = options.pop('macro').strip()
+    targets = options.pop('targets', name).strip().split()
+    macro_summation = {}
+
+    macro_summation.update(dict(buildout[macro]))
+
+    for output, input in (parse_target(name, target) for target in targets):
+        opt = zc.buildout.buildout.Options(
+                buildout,
+                output,
+                evaluate_macro(
+                    buildout, output, macro_summation, input, recipe))
+        if output == name:
+            # If we're targetting the invoker
+            options.update(opt)
+            options['recipe'] = options.get('recipe', 'zc.recipe.macro:empty')
+        else:
+            # If we're targetting some other section
+            buildout._data[output] = opt
+            opt._initialize()
+
+    #Make sure we have a recipe for this part, even if it is only the empty
+    #one.
+    if not options.get('recipe', None):
+        options['recipe'] = 'zc.recipe.macro:empty'
+
+    #Install the resulting recipe
+    reqs, entry = zc.buildout.buildout._recipe(options._data)
+    recipe_class = zc.buildout.buildout._install_and_load(
+        reqs, 'zc.buildout', entry, buildout)
+
+    __doing__ = 'Initializing part %s.', name
+    part = recipe_class(buildout, name, options)
+    return part
+
+
+class Empty(object):
+    def __init__(self, buildout, name, options):
+        self.buildout, self.name, self.options = buildout, name, options
+
+    def install(self):
+        return []
+
+    update = install
+
+    def uninstall(self):
+        pass
+
+
+class Test(object):
+
+    def __init__(self, buildout, name, options):
+        self.name = name
+        self.buildout = buildout
+        self.options = options
+
+    def install(self):
+        print '\n'.join("%s: %s" % item for item in sorted(
+            self.options.iteritems()))
+        return []
+
+    update = install
+
+    def uninstall(self):
+        pass


Property changes on: zc.recipe.macro/src/zc/recipe/macro/recipe.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: zc.recipe.macro/src/zc/recipe/macro/tests.py
===================================================================
--- zc.recipe.macro/src/zc/recipe/macro/tests.py	                        (rev 0)
+++ zc.recipe.macro/src/zc/recipe/macro/tests.py	2008-07-11 02:55:17 UTC (rev 88233)
@@ -0,0 +1,59 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+import os
+import re
+import zc.buildout.testing
+import zc.buildout.tests
+
+import unittest
+import zc.recipe.egg
+import zc.recipe.macro
+import zc.recipe.testrunner
+import zope.testing
+import zope.testing.doctest
+import zope.testing.renormalizing
+
+def setUp(test):
+    zc.buildout.testing.buildoutSetUp(test)
+
+    zc.buildout.testing.install('zope.testing', test)
+    zc.buildout.testing.install('zc.recipe.testrunner', test)
+    zc.buildout.testing.install('zc.recipe.egg', test)
+    zc.buildout.testing.install('zc.recipe.macro', test)
+    return test
+
+def test_suite():
+    optionflags = (zope.testing.doctest.NORMALIZE_WHITESPACE
+                   | zope.testing.doctest.ELLIPSIS
+                   | zope.testing.doctest.REPORT_NDIFF)
+    suite = unittest.TestSuite()
+    suite.addTest(
+        zope.testing.doctest.DocFileSuite(
+            'README.txt',
+            setUp=setUp, tearDown=zc.buildout.testing.buildoutTearDown,
+            checker=zope.testing.renormalizing.RENormalizing([
+               zc.buildout.testing.normalize_path,
+               zc.buildout.testing.normalize_script,
+               zc.buildout.testing.normalize_egg_py,
+               zc.buildout.tests.normalize_bang,
+               ]), optionflags=optionflags
+            ),)
+
+    return suite
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')
+
+


Property changes on: zc.recipe.macro/src/zc/recipe/macro/tests.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native



More information about the Checkins mailing list