[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