{ "info": { "author": "Jim Fulton", "author_email": "jim@zope.com", "bugtrack_url": null, "classifiers": [], "description": "============\nMeta-recipes\n============\n\nBuildout recipes provide reusable Python modules for common\nconfiguration tasks. The most widely used recipes tend to provide\nlow-level functions, like installing eggs or software distributions,\ncreating configuration files, and so on. The normal recipe framework\nis fairly well suited to building these general components.\n\nFull-blown applications may require many, often tens, of parts.\nDefining the many parts that make up an application can be tedious and\noften entails a lot of repetition. Buildout provides a number of\nmechanisms to avoid repetition, including merging of configuration\nfiles and macros, but these, while useful to an extent, don't scale\nvery well. Buildout isn't and shouldn't be a programming language.\n\nMeta-recipes allow us to bring Python to bear to provide higher-level\nabstractions for buildouts.\n\nA meta-recipe is a regular Python recipe that primarily operates by\ncreating parts. A meta recipe isn't merely a high level recipe. It's\na recipe that defers most of it's work to lower-level recipe by\nmanipulating the buildout database.\n\nUnfortunately, buildout doesn't yet provide a high-level API for\ncreating parts. It has a private low-level API which has been\npromoted to public (meaning it won't be broken by future release), and\nit's straightforward to write the needed high-level API, but it's\nannoying to repeat the high-level API in each meta recipe.\n\nThis small package provides the high-level API needed for meta recipes\nand a simple testing framework. It will be merged into a future\nbuildout release.\n\nA `presentation at PyCon 2011\n`_\ndescribed early work with meta recipes.\n\n.. contents::\n\nA simple meta-recipe example\n============================\n\nLet's look at a fairly simple meta-recipe example. First, consider a\nbuildout configuration that builds a database deployment::\n\n [buildout]\n parts = ctl pack\n\n [deployment]\n recipe = zc.recipe.deployment\n name = ample\n user = zope\n\n [ctl]\n recipe = zc.recipe.rhrc\n deployment = deployment\n chkconfig = 345 99 10\n parts = main\n\n [main]\n recipe = zc.zodbrecipes:server\n deployment = deployment\n address = 8100\n path = /var/databases/ample/main.fs\n zeo.conf =\n \n address ${:address}\n \n %import zc.zlibstorage\n \n \n path ${:path}\n \n \n\n [pack]\n recipe = zc.recipe.deployment:crontab\n deployment = deployment\n times = 1 2 * * 6\n command = ${buildout:bin-directory}/zeopack -d3 -t00 ${main:address}\n\n.. -> low_level\n\nThis buildout doesn't build software. Rather it builds configuration\nfor deploying a database configuration using already-deployed\nsoftware. For the purpose of this document, however, the details are\ntotally unimportant.\n\nRather than crafting the configuration above every time, we can write\na meta-recipe that crafts it for us. We'll use our meta-recipe as\nfollows::\n\n [buildout]\n parts = ample\n\n [ample]\n recipe = com.example.ample:db\n path = /var/databases/ample/main.fs\n\nThe idea here is that the meta recipe allows us to specify the minimal\ninformation necessary. A meta-recipe often automates policies and\nassumptions that are application and organization dependent. The\nexample above assumes, for example, that we want to pack to 3\ndays in the past on Saturdays.\n\nSo now, let's see the meta recipe that automates this::\n\n import zc.metarecipe\n\n class Recipe(zc.metarecipe.Recipe):\n\n def __init__(self, buildout, name, options):\n super(Recipe, self).__init__(buildout, name, options)\n\n self.parse('''\n [deployment]\n recipe = zc.recipe.deployment\n name = %s\n user = zope\n ''' % name)\n\n self['main'] = dict(\n recipe = 'zc.zodbrecipes:server',\n deployment = 'deployment',\n address = 8100,\n path = options['path'],\n **{\n 'zeo.conf': '''\n \n address ${:address}\n \n\n %import zc.zlibstorage\n\n \n \n path ${:path}\n \n \n '''}\n )\n\n self.parse('''\n [pack]\n recipe = zc.recipe.deployment:crontab\n deployment = deployment\n times = 1 2 * * 6\n command =\n ${buildout:bin-directory}/zeopack -d3 -t00 ${main:address}\n\n [ctl]\n recipe = zc.recipe.rhrc\n deployment = deployment\n chkconfig = 345 99 10\n parts = main\n ''')\n\n.. -> source\n\n >>> exec source\n\nThe meta recipe just adds parts to the buildout. It does this by\ncalling inherited __setitem__ and ``parse`` methods. The ``parse``\nmethod just takes a string in ``ConfigParser`` syntax. It's useful\nwhen we want to add static, or nearly static part data. The setitem\nsyntax is useful when we have non-trivial computation for part data.\n\nThe order that we add parts is important. When adding a part, any\nstring substitutions and other dependencies are evaluated, so the\nreferenced parts must be defined first. This is why, for example, the\n``pack`` part is added after the ``main`` part.\n\nNote that the meta recipe supplied an integer for one of the\noptions. In addition to strings, it's legal to supply integer and\nunicode values.\n\nTesting\n=======\n\nNow, let's test it. We'll test it without actually running\nbuildout. Rather, we'll use a faux buildout provided by the\nzc.metarecipe.testing module.\n\n >>> import zc.metarecipe.testing\n >>> buildout = zc.metarecipe.testing.Buildout()\n\n >>> _ = Recipe(buildout, 'ample', dict(path='/var/databases/ample/main.fs'))\n [deployment]\n name = ample\n recipe = zc.recipe.deployment\n user = zope\n [main]\n address = 8100\n deployment = deployment\n path = /var/databases/ample/main.fs\n recipe = zc.zodbrecipes:server\n zeo.conf = \n address ${:address}\n \n \n %import zc.zlibstorage\n \n \n \n path ${:path}\n \n \n [ctl]\n chkconfig = 345 99 10\n deployment = deployment\n parts = main\n recipe = zc.recipe.rhrc\n [pack]\n command = ${buildout:bin-directory}/zeopack -d3 -t00 ${main:address}\n deployment = deployment\n recipe = zc.recipe.deployment:crontab\n times = 1 2 * * 6\n\nWhen we call our recipe, it will add sections to the test buildout and\nthese are simply printed as added, so we can verify that the correct\ndata was generated.\n\nThat's pretty much it.\n\nChanges\n=======\n\n0.2.1 (2014-01-24)\n------------------\n\n- Fixed: When parsing configuration text, sections were input and\n evaluated at the same time in section sorted order. This\n caused problems if a section that sorted early referred to a\n section that sorted late.\n\n0.2.0 (2012-09-24)\n------------------\n\n- When setting option values, unicode and int values will be converted\n to strings. Other non-string values are rejected. Previously, it\n was easy to get errors from buildout when setting options with\n values read from ZooKeeper trees, which are unicode due to the use\n of JSON.\n\n- Fixed: When using the meta-recipe parse method, the order that\n resulting sections were added was non-deterministic, due to the\n way ConfigParser works. Not sections are added to a buildout\n in sortd order, by section name.\n\n0.1.0 (2012-05-31)\n------------------\n\nInitial release", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "UNKNOWN", "keywords": null, "license": "ZPL 2.1", "maintainer": null, "maintainer_email": null, "name": "zc.metarecipe", "package_url": "https://pypi.org/project/zc.metarecipe/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/zc.metarecipe/", "project_urls": { "Download": "UNKNOWN", "Homepage": "UNKNOWN" }, "release_url": "https://pypi.org/project/zc.metarecipe/0.2.1/", "requires_dist": null, "requires_python": null, "summary": "============", "version": "0.2.1" }, "last_serial": 980444, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "dbbf48613a1a75d184a83cc1103b8cff", "sha256": "59c963218e267949e7d053ad82902d81625c2ad16f52ad43027283b6b2ca561b" }, "downloads": -1, "filename": "zc.metarecipe-0.1.0.tar.gz", "has_sig": false, "md5_digest": "dbbf48613a1a75d184a83cc1103b8cff", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6804, "upload_time": "2012-05-31T19:22:42", "url": "https://files.pythonhosted.org/packages/be/06/a4e3d8aeeb0028add75639d43942cab69de991294c926837479a9a414d7e/zc.metarecipe-0.1.0.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "989d509247492d9543f95b64e49b0b1c", "sha256": "1e0510a2f6b233184198357e03da7a2549dd9f51ec8e383f4ca517c2333176a5" }, "downloads": -1, "filename": "zc.metarecipe-0.2.0.tar.gz", "has_sig": false, "md5_digest": "989d509247492d9543f95b64e49b0b1c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7531, "upload_time": "2012-09-24T17:53:57", "url": "https://files.pythonhosted.org/packages/1b/d9/fdfe7b0a85bb732f8068354278abc24350c0a295ef42020b02c14c94f39e/zc.metarecipe-0.2.0.tar.gz" } ], "0.2.1": [ { "comment_text": "", "digests": { "md5": "4550c1fcf0c980fcdc0c9d4a6a9fff3b", "sha256": "7fba976ef65d8e8c70b86ec6a77b2331ab5ab9fa988d1ec9d448d16a2bc848a2" }, "downloads": -1, "filename": "zc.metarecipe-0.2.1.tar.gz", "has_sig": false, "md5_digest": "4550c1fcf0c980fcdc0c9d4a6a9fff3b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7488, "upload_time": "2014-01-24T15:25:50", "url": "https://files.pythonhosted.org/packages/16/4a/6396dd27178e193cde04d9182c23e9ed8afa51205a388e73d1600f028309/zc.metarecipe-0.2.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "4550c1fcf0c980fcdc0c9d4a6a9fff3b", "sha256": "7fba976ef65d8e8c70b86ec6a77b2331ab5ab9fa988d1ec9d448d16a2bc848a2" }, "downloads": -1, "filename": "zc.metarecipe-0.2.1.tar.gz", "has_sig": false, "md5_digest": "4550c1fcf0c980fcdc0c9d4a6a9fff3b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7488, "upload_time": "2014-01-24T15:25:50", "url": "https://files.pythonhosted.org/packages/16/4a/6396dd27178e193cde04d9182c23e9ed8afa51205a388e73d1600f028309/zc.metarecipe-0.2.1.tar.gz" } ] }