{ "info": { "author": "Jim Fulton", "author_email": "jim@zope.com", "bugtrack_url": null, "classifiers": [], "description": "***********************\nUnix Deployment Support\n***********************\n\n.. contents::\n\nThe zc.recipe.deployment recipe provides support for deploying\napplications with multiple processes on Unix systems. (Perhaps support\nfor other systems will be added later.) It creates directories to hold\napplication instance configuration, log and run-time files. It also\nsets or reads options that can be read by other programs to find out\nwhere to place files:\n\n``cache-directory``\n The name of the directory where application instances should write\n cached copies of replacable data. This defaults to /var/cache/NAME,\n where NAME is the deployment name.\n\n``crontab-directory``\n The name of the directory in which cron jobs should be placed.\n This defaults to /etc/cron.d.\n\n``etc-directory``\n The name of the directory where configuration files should be\n placed. This defaults to /etc/NAME, where NAME is the deployment\n name.\n\n``var-prefix``\n The path of the directory where configuration should be stored for\n all applications. This defaults to /etc.\n\n``lib-directory``\n The name of the directory where application instances should write\n valuable data. This defaults to /var/lib/NAME, where NAME is the\n deployment name.\n\n``log-directory``\n The name of the directory where application instances should write\n their log files. This defaults to /var/log/NAME, where NAME is the\n deployment name.\n\n``logrotate-directory``\n The name of the directory where logrotate configuration files\n should be placed, typically, /etc/logrotate.d.\n\n``run-directory``\n The name of the directory where application instances should put\n their run-time files such as pid files and inter-process\n communication socket files. This defaults to /var/run/NAME, where\n NAME is the deployment name.\n\n``rc-directory``\n The name of the directory where run-control scripts should be\n installed. This defaults to /etc/init.d.\n\n``var-prefix``\n The path of the directory where data should be stored for all\n applications. This defaults to /var.\n\nDirectories traditionally placed in the /var hierarchy are created in\nsuch a way that the directories are owned by the user specified in the\n``user`` option and are writable by the user and the user's group.\nDirectories usually found in the /etc hierarchy are created owned by the\nuser specified by the ``etc-user`` setting (default to 'root') with the\nsame permissions\n\nA system-wide configuration file, zc.recipe.deployment.cfg, located in\nthe ``etc-prefix`` directory, can be used to specify the ``var-prefix``\nsetting. The file uses the Python-standard ConfigParser syntax::\n\n [deployment]\n var-prefix = /mnt/fatdisk\n\nNote that the section name is not related to the name of the deployment\nparts being built; this is a system-wide setting not specific to any\ndeployment. This is useful to identify very large partitions where\ncontrol over /var itself is difficult to achieve.\n\nChanges\n*******\n\n- Python 3 support.\n\n1.3.0 (2015-11-11)\n==================\n\n- Added an ``on-change`` option to the configuration recipe to run a\n command when a configuration file changes.\n\n1.1.0 (2013-11-04)\n==================\n\n- Do not touch an existing configuration file if the content hasn't\n changed.\n\n\n1.0.0 (2013-04-24)\n==================\n\n- Added a ``name`` option to the ``configuration`` recipe to allow\n explicit control of generated file paths.\n\n0.10.2 (2013-04-10)\n===================\n\n- Fix packaging bug.\n\n\n0.10.1 (2013-04-10)\n===================\n\n- Fix for 0.9 -> 0.10 .installed.cfg migration\n\n\n0.10.0 (2013-03-28)\n===================\n\n- Add ``etc-prefix`` and ``var-prefix`` to specify new locations of\n these entire trees. Final versions of these paths are exported.\n\n- Previously undocumented & untested ``etc``, ``log`` and ``run``\n settings are deprecated. Warnings are logged if their values are\n used.\n\n- Add ``cache-directory`` and ``lib-directory`` to the set of output\n directories.\n\n- Add system-wide configuration, allowing locations of the \"root\"\n directories to be specified for an entire machine.\n\n- Allow ``*-directory`` options (e.g. ``log-directory``) to be\n overridden by configuration data.\n\n\n0.9.0 (2011-11-21)\n==================\n\n- Fixed test dependencies.\n\n- Using Python's ``doctest`` module instead of deprecated\n ``zope.testing.doctest``.\n\n- Added a directory option for configuration to override default etc\n directory.\n\n\n0.8.0 (2010-05-18)\n==================\n\nFeatures Added\n--------------\n\nAdded recipe for updating configuration files that may shared by\nmultiple applications.\n\n0.7.1 (2010-03-05)\n==================\n\nBugs fixed\n----------\n\n- Fixed a serious bug that cause buildouts to fail when using new\n versions of the deployment recipe with older buildouts.\n\n- Made uninstall more tolerant of directories it's about to delete\n already being deleted.\n\n0.7.0 (2010-02-01)\n==================\n\nFeatures Added\n--------------\n\nYou can now specify a user for crontab entries that is different than\na deployment user.\n\n0.6 (2008-02-01)\n================\n\nFeatures Added\n--------------\n\nAdded the ability to specify a name independent of the section name.\nAlso, provide a name option for use by recipes.\n\nImportant note to recipe authors: Recipes should use the deployment\nname option rather than the deployment name when computing names of\ngenerated files.\n\n0.5 (Mar 23, 2007)\n==================\n\nFeatures Added\n--------------\n\nAdded recipe for generating crontab files in /etc/cron.d.\n\n0.4 (Mar 22, 2007)\n==================\n\nFeatures Added\n--------------\n\n- Added setting for the logrotate configuration directories.\n\nBugs Fixed\n----------\n\n- The documentation gave the wrong name for the crontab-directory option.\n\n0.3 (Feb 14, 2007)\n==================\n\nFeatures Added\n--------------\n\n- Added a configuration recipe for creating configuration files.\n\n0.2.1 (Feb 13, 2007)\n====================\n\n- Fixed bug in setup file.\n\n0.2 (Feb 7, 2007)\n=================\n\nBugs Fixed\n----------\n\n- Non-empty log and run directories were deleated in un- and\n re-install.\n\nDetailed Documentation\n**********************\n\nUsing the deployment recipe is pretty simple. Just specify a\ndeployment name, specified via the part name, and a deployment user.\n\nLet's add a deployment to a sample buildout:\n\n >>> write('buildout.cfg',\n ... '''\n ... [buildout]\n ... parts = foo\n ...\n ... [foo]\n ... prefix = %s\n ... recipe = zc.recipe.deployment\n ... user = %s\n ... etc-user = %s\n ... ''' % (sample_buildout, user, user))\n\n >>> from six import print_\n >>> print_(system(join('bin', 'buildout')), end='')\n Installing foo.\n zc.recipe.deployment:\n Creating 'PREFIX/etc/foo',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/var/cache/foo',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/var/lib/foo',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/var/log/foo',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/var/run/foo',\n mode 750, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/etc/cron.d',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/etc/init.d',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/etc/logrotate.d',\n mode 755, user 'USER', group 'GROUP'\n\nNote that we are providing a prefix and an etc-user here. These options\ndefault to '/' and 'root', respectively.\n\nNow we can see that directories named foo in PREFIX/etc, PREFIX/var/log and\nPREFIX/var/run have been created:\n\n >>> import os\n >>> print_(ls(os.path.join(sample_buildout, 'etc/foo')))\n drwxr-xr-x USER GROUP PREFIX/etc/foo\n\n >>> print_(ls(os.path.join(sample_buildout, 'var/cache/foo')))\n drwxr-xr-x USER GROUP PREFIX/var/cache/foo\n\n >>> print_(ls(os.path.join(sample_buildout, 'var/lib/foo')))\n drwxr-xr-x USER GROUP PREFIX/var/lib/foo\n\n >>> print_(ls(os.path.join(sample_buildout, 'var/log/foo')))\n drwxr-xr-x USER GROUP PREFIX/var/log/foo\n\n >>> print_(ls(os.path.join(sample_buildout, 'var/run/foo')))\n drwxr-x--- USER GROUP PREFIX/var/run/foo\n\nBy looking at .installed.cfg, we can see the options available for use\nby other recipes:\n\n >>> cat('.installed.cfg') # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE\n [buildout]\n ...\n [foo]\n __buildout_installed__ =\n ...\n cache-directory = PREFIX/var/cache/foo\n crontab-directory = PREFIX/etc/cron.d\n etc-directory = PREFIX/etc/foo\n etc-prefix = PREFIX/etc\n etc-user = USER\n lib-directory = PREFIX/var/lib/foo\n log-directory = PREFIX/var/log/foo\n logrotate-directory = PREFIX/etc/logrotate.d\n name = foo\n prefix = PREFIX\n rc-directory = PREFIX/etc/init.d\n recipe = zc.recipe.deployment\n run-directory = PREFIX/var/run/foo\n user = USER\n var-prefix = PREFIX/var\n\nIf we uninstall, then the directories are removed.\n\n >>> print_(system(join('bin', 'buildout')+' buildout:parts='), end='')\n Uninstalling foo.\n Running uninstall recipe.\n zc.recipe.deployment: Removing 'PREFIX/etc/foo'\n zc.recipe.deployment: Removing 'PREFIX/etc/cron.d'.\n zc.recipe.deployment: Removing 'PREFIX/etc/init.d'.\n zc.recipe.deployment: Removing 'PREFIX/etc/logrotate.d'.\n zc.recipe.deployment: Removing 'PREFIX/var/cache/foo'.\n zc.recipe.deployment: Removing 'PREFIX/var/lib/foo'.\n zc.recipe.deployment: Removing 'PREFIX/var/log/foo'.\n zc.recipe.deployment: Removing 'PREFIX/var/run/foo'.\n\n >>> import os\n >>> os.path.exists(os.path.join(sample_buildout, 'etc/foo'))\n False\n >>> os.path.exists(os.path.join(sample_buildout, 'var/cache/foo'))\n False\n >>> os.path.exists(os.path.join(sample_buildout, 'var/lib/foo'))\n False\n >>> os.path.exists(os.path.join(sample_buildout, 'var/log/foo'))\n False\n >>> os.path.exists(os.path.join(sample_buildout, 'var/run/foo'))\n False\n\nThe cache, lib, log and run directories are only removed if they are empty.\nTo see that, we'll put a file in each of the directories created:\n\n >>> print_(system(join('bin', 'buildout')), end='')\n ... # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE\n Installing foo.\n zc.recipe.deployment:\n Creating 'PREFIX/etc/foo',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/var/cache/foo',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/var/lib/foo',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/var/log/foo',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/var/run/foo',\n mode 750, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/etc/cron.d',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/etc/init.d',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/etc/logrotate.d',\n mode 755, user 'USER', group 'GROUP'\n\n >>> write(os.path.join(sample_buildout, 'etc/foo/x'), '')\n >>> write(os.path.join(sample_buildout, 'var/cache/foo/x'), '')\n >>> write(os.path.join(sample_buildout, 'var/lib/foo/x'), '')\n >>> write(os.path.join(sample_buildout, 'var/log/foo/x'), '')\n >>> write(os.path.join(sample_buildout, 'var/run/foo/x'), '')\n\nAnd then uninstall:\n\n >>> print_(system(join('bin', 'buildout')+' buildout:parts='), end='')\n Uninstalling foo.\n Running uninstall recipe.\n zc.recipe.deployment: Removing 'PREFIX/etc/foo'\n zc.recipe.deployment: Removing 'PREFIX/etc/cron.d'.\n zc.recipe.deployment: Removing 'PREFIX/etc/init.d'.\n zc.recipe.deployment: Removing 'PREFIX/etc/logrotate.d'.\n zc.recipe.deployment: Can't remove non-empty directory 'PREFIX/var/cache/foo'.\n zc.recipe.deployment: Can't remove non-empty directory 'PREFIX/var/lib/foo'.\n zc.recipe.deployment: Can't remove non-empty directory 'PREFIX/var/log/foo'.\n zc.recipe.deployment: Can't remove non-empty directory 'PREFIX/var/run/foo'.\n\n >>> os.path.exists(os.path.join(sample_buildout, 'etc/foo'))\n False\n\n >>> print_(ls(os.path.join(sample_buildout, 'var/cache/foo')))\n drwxr-xr-x USER GROUP PREFIX/var/cache/foo\n\n >>> print_(ls(os.path.join(sample_buildout, 'var/lib/foo')))\n drwxr-xr-x USER GROUP PREFIX/var/lib/foo\n\n >>> print_(ls(os.path.join(sample_buildout, 'var/log/foo')))\n drwxr-xr-x USER GROUP PREFIX/var/log/foo\n\n >>> print_(ls(os.path.join(sample_buildout, 'var/run/foo')))\n drwxr-x--- USER GROUP PREFIX/var/run/foo\n\nHere we see that the var and run directories are kept. The etc\ndirectory is discarded because only buildout recipes should write to\nit and all of its data are expendible.\n\nIf we reinstall, remove the files, and uninstall, then the directories\nare removed:\n\n >>> print_(system(join('bin', 'buildout')), end='')\n Installing foo.\n zc.recipe.deployment:\n Creating 'PREFIX/etc/foo',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Updating 'PREFIX/var/cache/foo',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Updating 'PREFIX/var/lib/foo',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Updating 'PREFIX/var/log/foo',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Updating 'PREFIX/var/run/foo',\n mode 750, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/etc/cron.d',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/etc/init.d',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/etc/logrotate.d',\n mode 755, user 'USER', group 'GROUP'\n\n >>> os.remove(os.path.join(sample_buildout, 'var/cache/foo/x'))\n >>> os.remove(os.path.join(sample_buildout, 'var/lib/foo/x'))\n >>> os.remove(os.path.join(sample_buildout, 'var/log/foo/x'))\n >>> os.remove(os.path.join(sample_buildout, 'var/run/foo/x'))\n\n >>> print_(system(join('bin', 'buildout')+' buildout:parts='), end='')\n Uninstalling foo.\n Running uninstall recipe.\n zc.recipe.deployment: Removing 'PREFIX/etc/foo'\n zc.recipe.deployment: Removing 'PREFIX/etc/cron.d'.\n zc.recipe.deployment: Removing 'PREFIX/etc/init.d'.\n zc.recipe.deployment: Removing 'PREFIX/etc/logrotate.d'.\n zc.recipe.deployment: Removing 'PREFIX/var/cache/foo'.\n zc.recipe.deployment: Removing 'PREFIX/var/lib/foo'.\n zc.recipe.deployment: Removing 'PREFIX/var/log/foo'.\n zc.recipe.deployment: Removing 'PREFIX/var/run/foo'.\n\n >>> os.path.exists('' + os.path.join(sample_buildout, 'PREFIX/etc/foo'))\n False\n >>> os.path.exists('' + os.path.join(sample_buildout, 'PREFIX/var/cache/foo'))\n False\n >>> os.path.exists('' + os.path.join(sample_buildout, 'PREFIX/var/lib/foo'))\n False\n >>> os.path.exists('' + os.path.join(sample_buildout, 'PREFIX/var/log/foo'))\n False\n >>> os.path.exists('' + os.path.join(sample_buildout, 'PREFIX/var/run/foo'))\n False\n\nPrior to zc.recipe.deployment 0.10.0, some directories (eg., cache-directory,\nlib-directory) were not managed by zc.recipe.deployment. So on uninstall, we\ncan expect any nonexistent directory keys to be silently ignored.\n\n >>> _ = system(join('bin', 'buildout')), # doctest: +NORMALIZE_WHITESPACE\n >>> new_installed_contents = \"\"\n >>> with open(\n ... os.path.join(sample_buildout, \".installed.cfg\")) as fi:\n ... for line in fi.readlines():\n ... if (not line.startswith(\"cache-directory = \") and\n ... not line.startswith(\"lib-directory = \")):\n ... new_installed_contents += line\n >>> with open(\n ... os.path.join(sample_buildout, \".installed.cfg\"), 'w') as fi:\n ... _ = fi.write(new_installed_contents)\n >>> print_(system(join('bin', 'buildout')+' buildout:parts='), end='')\n Uninstalling foo.\n Running uninstall recipe.\n zc.recipe.deployment: Removing '/tmp/tmpcokpi_buildoutSetUp/_TEST_/sample-buildout/etc/foo'\n zc.recipe.deployment: Removing '/tmp/tmpcokpi_buildoutSetUp/_TEST_/sample-buildout/etc/cron.d'.\n zc.recipe.deployment: Removing '/tmp/tmpcokpi_buildoutSetUp/_TEST_/sample-buildout/etc/init.d'.\n zc.recipe.deployment: Removing '/tmp/tmpcokpi_buildoutSetUp/_TEST_/sample-buildout/etc/logrotate.d'.\n zc.recipe.deployment: Removing '/tmp/tmpcokpi_buildoutSetUp/_TEST_/sample-buildout/var/log/foo'.\n zc.recipe.deployment: Removing '/tmp/tmpcokpi_buildoutSetUp/_TEST_/sample-buildout/var/run/foo'.\n\nWe'll finish the cleanup our modified .installed.cfg missed.\n\n >>> os.removedirs(os.path.join(sample_buildout, 'var/cache/foo'))\n >>> os.removedirs(os.path.join(sample_buildout, 'var/lib/foo'))\n\n\nDeployment Name\n===============\n\nThe deployment name is used for naming generated files and directories.\nThe deployment name defaults to the section name, but the deployment\nname can be specified explicitly:\n\n >>> write('buildout.cfg',\n ... '''\n ... [buildout]\n ... parts = foo\n ...\n ... [foo]\n ... recipe = zc.recipe.deployment\n ... prefix = %s\n ... name = bar\n ... user = %s\n ... etc-user = %s\n ... ''' % (sample_buildout, user, user))\n\n >>> print_(system(join('bin', 'buildout')), end='')\n Installing foo.\n zc.recipe.deployment:\n Creating 'PREFIX/etc/bar',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/var/cache/bar',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/var/lib/bar',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/var/log/bar',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/var/run/bar',\n mode 750, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/etc/cron.d',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/etc/init.d',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/etc/logrotate.d',\n mode 755, user 'USER', group 'GROUP'\n\n >>> print_(ls(os.path.join(sample_buildout, 'etc/bar')))\n drwxr-xr-x USER GROUP PREFIX/etc/bar\n\n >>> print_(ls(os.path.join(sample_buildout, 'var/cache/bar')))\n drwxr-xr-x USER GROUP PREFIX/var/cache/bar\n\n >>> print_(ls(os.path.join(sample_buildout, 'var/lib/bar')))\n drwxr-xr-x USER GROUP PREFIX/var/lib/bar\n\n >>> print_(ls(os.path.join(sample_buildout, 'var/log/bar')))\n drwxr-xr-x USER GROUP PREFIX/var/log/bar\n\n >>> print_(ls(os.path.join(sample_buildout, 'var/run/bar')))\n drwxr-x--- USER GROUP PREFIX/var/run/bar\n\n >>> cat('.installed.cfg') # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE\n [buildout]\n installed_develop_eggs =\n parts = foo\n \n [foo]\n __buildout_installed__ =\n ...\n cache-directory = PREFIX/var/cache/bar\n crontab-directory = PREFIX/etc/cron.d\n etc-directory = PREFIX/etc/bar\n etc-prefix = PREFIX/etc\n etc-user = USER\n lib-directory = PREFIX/var/lib/bar\n log-directory = PREFIX/var/log/bar\n logrotate-directory = PREFIX/etc/logrotate.d\n name = bar\n prefix = PREFIX\n rc-directory = PREFIX/etc/init.d\n recipe = zc.recipe.deployment\n run-directory = PREFIX/var/run/bar\n user = USER\n var-prefix = PREFIX/var\n\nNote (here and earlier) that the options include the name option,\nwhich defaults to the part name. Other parts that use the deployment\nname should use the name option rather than the part name.\n\n\nConfiguration files\n===================\n\nNormally, configuration files are created by specialized recipes.\nSometimes, it's useful to specify configuration files in a buildout\nconfiguration file. The zc.recipe.deployment:configuration recipe can be\nused to do that.\n\nLet's add a configuration file to our buildout:\n\n >>> write('buildout.cfg',\n ... '''\n ... [buildout]\n ... parts = foo x.cfg\n ...\n ... [foo]\n ... recipe = zc.recipe.deployment\n ... prefix = %s\n ... user = %s\n ... etc-user = %s\n ...\n ... [x.cfg]\n ... recipe = zc.recipe.deployment:configuration\n ... text = xxx\n ... yyy\n ... zzz\n ... ''' % (sample_buildout, user, user))\n\n >>> print_(system(join('bin', 'buildout')), end='')\n Uninstalling foo.\n Running uninstall recipe.\n zc.recipe.deployment: Removing 'PREFIX/etc/bar'\n zc.recipe.deployment: Removing 'PREFIX/etc/cron.d'.\n zc.recipe.deployment: Removing 'PREFIX/etc/init.d'.\n zc.recipe.deployment: Removing 'PREFIX/etc/logrotate.d'.\n zc.recipe.deployment: Removing 'PREFIX/var/cache/bar'.\n zc.recipe.deployment: Removing 'PREFIX/var/lib/bar'.\n zc.recipe.deployment: Removing 'PREFIX/var/log/bar'.\n zc.recipe.deployment: Removing 'PREFIX/var/run/bar'.\n Installing foo.\n zc.recipe.deployment:\n Creating 'PREFIX/etc/foo',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/var/cache/foo',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/var/lib/foo',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/var/log/foo',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/var/run/foo',\n mode 750, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/etc/cron.d',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/etc/init.d',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/etc/logrotate.d',\n mode 755, user 'USER', group 'GROUP'\n Installing x.cfg.\n\nBy default, the configuration is installed as a part:\n\n >>> cat('parts', 'x.cfg')\n xxx\n yyy\n zzz\n\nIf a deployment is specified, then the file is placed in the\ndeployment etc directory:\n\n >>> write('buildout.cfg',\n ... '''\n ... [buildout]\n ... parts = foo x.cfg\n ...\n ... [foo]\n ... recipe = zc.recipe.deployment\n ... prefix = %s\n ... user = %s\n ... etc-user = %s\n ...\n ... [x.cfg]\n ... recipe = zc.recipe.deployment:configuration\n ... text = xxx\n ... yyy\n ... zzz\n ... deployment = foo\n ... ''' % (sample_buildout, user, user))\n\n >>> print_(system(join('bin', 'buildout')), end='')\n Uninstalling x.cfg.\n Updating foo.\n Installing x.cfg.\n zc.recipe.deployment:\n Updating 'PREFIX/etc/foo',\n mode 755, user 'USER', group 'GROUP'\n\n >>> os.path.exists(join('parts', 'x.cfg'))\n False\n\n >>> cat(os.path.join(sample_buildout, 'etc/foo/x.cfg'))\n xxx\n yyy\n zzz\n\nIf a directory is specified, then the file is placed in the directory.\n\n >>> write('buildout.cfg',\n ... '''\n ... [buildout]\n ... parts = foo x.cfg\n ...\n ... [foo]\n ... recipe = zc.recipe.deployment\n ... prefix = %s\n ... user = %s\n ... etc-user = %s\n ...\n ... [x.cfg]\n ... recipe = zc.recipe.deployment:configuration\n ... text = xxx\n ... yyy\n ... zzz\n ... directory = etc/foobar\n ... deployment = foo\n ... ''' % (sample_buildout, user, user))\n\n >>> print_(system(join('bin', 'buildout')), end='')\n Uninstalling x.cfg.\n Updating foo.\n Installing x.cfg.\n zc.recipe.deployment:\n Creating 'PREFIX/etc/foobar',\n mode 755, user 'USER', group 'GROUP'\n\n >>> os.path.exists(join('parts', 'x.cfg'))\n False\n >>> os.path.exists(join(sample_buildout, 'etc/foo/x.cfg'))\n False\n\n >>> cat(os.path.join(sample_buildout, 'etc/foobar/x.cfg'))\n xxx\n yyy\n zzz\n\nA directory option works only with a deployment option.\n\n >>> write('buildout.cfg',\n ... '''\n ... [buildout]\n ... parts = foo x.cfg\n ...\n ... [foo]\n ... recipe = zc.recipe.deployment\n ... prefix = %s\n ... user = %s\n ... etc-user = %s\n ...\n ... [x.cfg]\n ... recipe = zc.recipe.deployment:configuration\n ... text = xxx\n ... yyy\n ... zzz\n ... directory = etc/foobar\n ... ''' % (sample_buildout, user, user))\n\n >>> print_(system(join('bin', 'buildout')), end='')\n Uninstalling x.cfg.\n Updating foo.\n Installing x.cfg.\n\n >>> os.path.exists(join('parts', 'x.cfg'))\n True\n >>> os.path.exists(join(sample_buildout, 'etc/foobar/x.cfg'))\n False\n\n >>> cat('parts', 'x.cfg')\n xxx\n yyy\n zzz\n\nWe can read data from a file rather than specifying in the\nconfiguration:\n\n >>> write('x.in', '1\\n2\\n3\\n')\n\n >>> write('buildout.cfg',\n ... '''\n ... [buildout]\n ... parts = foo x.cfg\n ...\n ... [foo]\n ... recipe = zc.recipe.deployment\n ... prefix = %s\n ... user = %s\n ... etc-user = %s\n ...\n ... [x.cfg]\n ... recipe = zc.recipe.deployment:configuration\n ... file = x.in\n ... deployment = foo\n ... ''' % (sample_buildout, user, user))\n\n >>> print_(system(join('bin', 'buildout')), end='')\n Uninstalling x.cfg.\n Updating foo.\n Installing x.cfg.\n zc.recipe.deployment:\n Updating 'PREFIX/etc/foo',\n mode 755, user 'USER', group 'GROUP'\n\n >>> cat(os.path.join(sample_buildout, 'etc/foo/x.cfg'))\n 1\n 2\n 3\n\nThe recipe sets a location option that can be used by other recipes:\n\n >>> cat('.installed.cfg') # doctest: +ELLIPSIS\n [buildout]\n ...\n [x.cfg]\n ...\n location = PREFIX/etc/foo/x.cfg\n ...\n\nBy default, the part name is used as the file name. You can specify a\nname explicitly using the name option:\n\n >>> write('buildout.cfg',\n ... '''\n ... [buildout]\n ... parts = foo x.cfg\n ...\n ... [foo]\n ... recipe = zc.recipe.deployment\n ... prefix = %s\n ... user = %s\n ... etc-user = %s\n ...\n ... [x.cfg]\n ... recipe = zc.recipe.deployment:configuration\n ... name = y.cfg\n ... text = this is y\n ... deployment = foo\n ... ''' % (sample_buildout, user, user))\n\n >>> print_(system(join('bin', 'buildout')), end='')\n Uninstalling x.cfg.\n Updating foo.\n Installing x.cfg.\n zc.recipe.deployment:\n Updating 'PREFIX/etc/foo',\n mode 755, user 'USER', group 'GROUP'\n\n >>> cat(os.path.join(sample_buildout, 'etc/foo/y.cfg'))\n this is y\n\nIf name is given, only the file so named is created:\n\n >>> os.path.exists(os.path.join(sample_buildout, 'etc', 'foo', 'x.cfg'))\n False\n\nThe name can be a path, or even absolute:\n\n >>> write('buildout.cfg',\n ... '''\n ... [buildout]\n ... parts = foo x.cfg\n ...\n ... [foo]\n ... recipe = zc.recipe.deployment\n ... prefix = %s\n ... user = %s\n ... etc-user = %s\n ...\n ... [x.cfg]\n ... recipe = zc.recipe.deployment:configuration\n ... name = ${buildout:directory}/y.cfg\n ... text = this is y also\n ... deployment = foo\n ... ''' % (sample_buildout, user, user))\n\n >>> print_(system(join('bin', 'buildout')), end='')\n Uninstalling x.cfg.\n Updating foo.\n Installing x.cfg.\n zc.recipe.deployment:\n Updating 'PREFIX/etc/foo',\n mode 755, user 'USER', group 'GROUP'\n\n >>> cat('y.cfg')\n this is y also\n\nIf the content of the configuration file is unchanged between builds,\nand the path hasn't been changed, the file isn't actually written in\nsubsequent builds. This is helpful if processes that use the file watch\nfor changes.\n\n >>> mod_time = os.stat('y.cfg').st_mtime\n\n >>> print_(system(join('bin', 'buildout')), end='')\n Updating foo.\n Updating x.cfg.\n zc.recipe.deployment:\n Updating 'PREFIX/etc/foo',\n mode 755, user 'USER', group 'GROUP'\n\n >>> os.stat('y.cfg').st_mtime == mod_time\n True\n\nRunning a command when a configuration file changes\n---------------------------------------------------\n\nOften, when working with configuration files, you'll need to restart\nprocesses when configuration files change. You can specify an\n``on-change`` option that takes a command to run whenever a\nconfiguration file changes:\n\n >>> write('buildout.cfg',\n ... '''\n ... [buildout]\n ... parts = foo x.cfg\n ...\n ... [foo]\n ... recipe = zc.recipe.deployment\n ... prefix = %s\n ... user = %s\n ... etc-user = %s\n ...\n ... [x.cfg]\n ... recipe = zc.recipe.deployment:configuration\n ... name = ${buildout:directory}/y.cfg\n ... text = this is y\n ... deployment = foo\n ... on-change = echo /etc/init.d/x start\n ... ''' % (sample_buildout, user, user))\n\n >>> print_(system(join('bin', 'buildout')), end='')\n Uninstalling x.cfg.\n Updating foo.\n Installing x.cfg.\n zc.recipe.deployment:\n Updating 'PREFIX/etc/foo',\n mode 755, user 'USER', group 'GROUP'\n /etc/init.d/x start\n\n.. test\n\n\n If we run this again, so the file doesn't change, then the command\n isn't run:\n\n >>> print_(system(join('bin', 'buildout')), end='')\n ... # doctest: +NORMALIZE_WHITESPACE\n Updating foo.\n Updating x.cfg.\n zc.recipe.deployment:\n Updating 'PREFIX/etc/foo',\n mode 755, user 'USER', group 'GROUP'\n\n If we screw up the command, buildout will see it:\n\n\n >>> write('buildout.cfg',\n ... '''\n ... [buildout]\n ... parts = foo x.cfg\n ...\n ... [foo]\n ... recipe = zc.recipe.deployment\n ... prefix = %s\n ... user = %s\n ... etc-user = %s\n ...\n ... [x.cfg]\n ... recipe = zc.recipe.deployment:configuration\n ... name = ${buildout:directory}/y.cfg\n ... text = this is y\n ... deployment = foo\n ... on-change = echoxxx /etc/init.d/x start\n ... ''' % (sample_buildout, user, user))\n\n >>> print_(system(join('bin', 'buildout')), end='')\n ... # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE\n Uninstalling x.cfg.\n Updating foo.\n Installing x.cfg.\n zc.recipe.deployment:\n Updating 'PREFIX/etc/foo',\n mode 755, user 'USER', group 'GROUP'\n ... echoxxx: not found\n While:\n Installing x.cfg.\n \n An internal error occurred due to a bug in either zc.buildout or in a\n recipe being used:\n Traceback (most recent call last):\n ...\n SystemError: 'echoxxx /etc/init.d/x start' failed\n\n\nCron support\n============\n\nThe crontab recipe provides support for creating crontab files. It\nuses a times option to specify times to run the command and a command\noption containing the command.\n\n >>> write('buildout.cfg',\n ... '''\n ... [buildout]\n ... parts = foo cron\n ...\n ... [foo]\n ... recipe = zc.recipe.deployment\n ... prefix = %s\n ... user = %s\n ... etc-user = %s\n ...\n ... [cron]\n ... recipe = zc.recipe.deployment:crontab\n ... times = 30 23 * * *\n ... command = echo hello world!\n ... deployment = foo\n ... ''' % (sample_buildout, user, user))\n\n >>> print_(system(join('bin', 'buildout')), end='')\n Updating foo.\n Installing cron.\n\nThis example creates PREFIX/etc/cron.d/foo-cron\n\n >>> open(os.path.join(sample_buildout, 'etc/cron.d/foo-cron')).read()\n '30 23 * * *\\tUSER\\techo hello world!\\n'\n\n.. make sure cron recipe honors deployment name option:\n\n >>> write('buildout.cfg',\n ... '''\n ... [buildout]\n ... parts = foo cron\n ...\n ... [foo]\n ... recipe = zc.recipe.deployment\n ... prefix = %s\n ... name = bar\n ... user = %s\n ... etc-user = %s\n ...\n ... [cron]\n ... recipe = zc.recipe.deployment:crontab\n ... times = 30 23 * * *\n ... command = echo hello world!\n ... deployment = foo\n ... ''' % (sample_buildout, user, user))\n\n >>> print_(system(join('bin', 'buildout')), end='')\n Uninstalling cron.\n Uninstalling foo.\n Running uninstall recipe.\n zc.recipe.deployment: Removing 'PREFIX/etc/foo'\n zc.recipe.deployment: Removing 'PREFIX/etc/cron.d'.\n zc.recipe.deployment: Removing 'PREFIX/etc/init.d'.\n zc.recipe.deployment: Removing 'PREFIX/etc/logrotate.d'.\n zc.recipe.deployment: Removing 'PREFIX/var/cache/foo'.\n zc.recipe.deployment: Removing 'PREFIX/var/lib/foo'.\n zc.recipe.deployment: Removing 'PREFIX/var/log/foo'.\n zc.recipe.deployment: Removing 'PREFIX/var/run/foo'.\n Installing foo.\n zc.recipe.deployment:\n Creating 'PREFIX/etc/bar',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/var/cache/bar',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/var/lib/bar',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/var/log/bar',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/var/run/bar',\n mode 750, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/etc/cron.d',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/etc/init.d',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/etc/logrotate.d',\n mode 755, user 'USER', group 'GROUP'\n Installing cron.\n\n >>> open(os.path.join(sample_buildout, 'etc/cron.d/bar-cron')).read()\n '30 23 * * *\\tUSER\\techo hello world!\\n'\n\nThe crontab recipe gets its user from the buildout's deployment by default,\nbut it doesn't have to.\n\n >>> write('buildout.cfg',\n ... '''\n ... [buildout]\n ... parts = foo cron\n ...\n ... [foo]\n ... recipe = zc.recipe.deployment\n ... name = bar\n ... prefix = %s\n ... user = %s\n ... etc-user = %s\n ...\n ... [cron]\n ... recipe = zc.recipe.deployment:crontab\n ... times = 30 23 * * *\n ... user = bob\n ... command = echo hello world!\n ... deployment = foo\n ... ''' % (sample_buildout, user, user))\n\n >>> print_(system(join('bin', 'buildout')), end='')\n Uninstalling cron.\n Updating foo.\n Installing cron.\n\n >>> open('etc/cron.d/bar-cron').read()\n '30 23 * * *\\tbob\\techo hello world!\\n'\n\n\n.. edge case\n\n uninstall with no stored prefix\n\n >>> installed = [l for l in open('.installed.cfg')\n ... if not l.startswith('prefix =')]\n >>> _ = open('.installed.cfg', 'w').write(''.join(installed))\n\n uninstall with some directories already gone:\n\n >>> rmdir(sample_buildout, 'etc', 'bar')\n >>> rmdir(sample_buildout, 'var', 'run')\n\n >>> write('buildout.cfg',\n ... '''\n ... [buildout]\n ... parts =\n ... ''')\n\n >>> print_(system(join('bin', 'buildout')), end='')\n Uninstalling cron.\n Uninstalling foo.\n Running uninstall recipe.\n zc.recipe.deployment: Removing 'PREFIX/var/cache/bar'.\n zc.recipe.deployment: Removing 'PREFIX/var/lib/bar'.\n zc.recipe.deployment: Removing 'PREFIX/var/log/bar'.\n\n\n.. cleanup\n\n >>> print_(system(join('bin', 'buildout')+' buildout:parts='), end='')\n\n >>> os.path.exists(os.path.join(sample_buildout, 'etc/cron.d/bar-cron'))\n False\n\n\nSharedConfig\n============\n\nThis recipe can be used to update configuration files that are shared by\nmultiple applications. The absolute path of the file must be specified.\nAlso, the configuration files must accept comments that start with \"#\".\n\nLike the configuration recipe, the content to add in the configuration file can\nbe provided using the \"text\" or the \"file\" option.\n\nFirst let's create a file that will be used as the shared configuration file.\n\n >>> _ = open('y.cfg', 'w').write(\n ... '''Some\n ... existing\n ... configuration\n ... ''')\n\nWe now create our buildout configuration and use the \"sharedconfig\" recipe and\nrun buildout.\n\n >>> write('buildout.cfg',\n ... '''\n ... [buildout]\n ... parts = foo y.cfg\n ...\n ... [foo]\n ... recipe = zc.recipe.deployment\n ... prefix = %s\n ... user = %s\n ... etc-user = %s\n ...\n ... [y.cfg]\n ... recipe = zc.recipe.deployment:sharedconfig\n ... path = y.cfg\n ... deployment = foo\n ... text = xxx\n ... yyy\n ... zzz\n ... ''' % (sample_buildout, user, user))\n\n >>> print_(system(join('bin', 'buildout')), end='')\n Installing foo.\n zc.recipe.deployment:\n Creating 'PREFIX/etc/foo',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/var/cache/foo',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/var/lib/foo',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/var/log/foo',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/var/run/foo',\n mode 750, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Updating 'PREFIX/etc/cron.d',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Updating 'PREFIX/etc/init.d',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Updating 'PREFIX/etc/logrotate.d',\n mode 755, user 'USER', group 'GROUP'\n Installing y.cfg.\n\n >>> print_(open('y.cfg', 'r').read())\n Some\n existing\n configuration\n \n #[foo_y.cfg DO NOT MODIFY LINES FROM HERE#\n xxx\n yyy\n zzz\n #TILL HERE foo_y.cfg]#\n \n\nRunning buildout again without modifying the configuration leaves the file the\nsame.\n\n >>> print_(system(join('bin', 'buildout')), end='')\n Updating foo.\n Updating y.cfg.\n\n >>> print_(open('y.cfg', 'r').read())\n Some\n existing\n configuration\n \n #[foo_y.cfg DO NOT MODIFY LINES FROM HERE#\n xxx\n yyy\n zzz\n #TILL HERE foo_y.cfg]#\n \n\nIf we add some more lines to the file\n\n >>> _ = open('y.cfg', 'a').write(\n ... '''Some\n ... additional\n ... configuration\n ... ''')\n\nand run buildout again, but this time after modifying the configuration for\n\"y.cfg\", the sections will be moved to the end of the file.\n\n >>> write('buildout.cfg',\n ... '''\n ... [buildout]\n ... parts = foo y.cfg\n ...\n ... [foo]\n ... recipe = zc.recipe.deployment\n ... prefix = %s\n ... user = %s\n ... etc-user = %s\n ...\n ... [y.cfg]\n ... recipe = zc.recipe.deployment:sharedconfig\n ... path = y.cfg\n ... deployment = foo\n ... text = 111\n ... 222\n ... 333\n ... ''' % (sample_buildout, user, user))\n\n >>> print_(system(join('bin', 'buildout')), end='')\n Uninstalling y.cfg.\n Running uninstall recipe.\n Updating foo.\n Installing y.cfg.\n\n >>> print_(open('y.cfg', 'r').read())\n Some\n existing\n configuration\n Some\n additional\n configuration\n \n #[foo_y.cfg DO NOT MODIFY LINES FROM HERE#\n 111\n 222\n 333\n #TILL HERE foo_y.cfg]#\n \n\nThe text to append to the shared configuration file can also be provided via a\nfile.\n\n >>> write('x.cfg', '''\n ... [foo]\n ... a = 1\n ... b = 2\n ...\n ... [log]\n ... c = 1\n ... ''')\n\n >>> write('buildout.cfg',\n ... '''\n ... [buildout]\n ... parts = foo y.cfg\n ...\n ... [foo]\n ... recipe = zc.recipe.deployment\n ... prefix = %s\n ... user = %s\n ... etc-user = %s\n ...\n ... [y.cfg]\n ... recipe = zc.recipe.deployment:sharedconfig\n ... path = %s/etc/z.cfg\n ... deployment = foo\n ... file = x.cfg\n ... ''' % (sample_buildout, user, user, sample_buildout))\n >>> print_(system(join('bin', 'buildout')), end='')\n While:\n Installing.\n Getting section y.cfg.\n Initializing section y.cfg.\n Error: Path 'PREFIX/etc/z.cfg' does not exist\n\nOops. The path of the configuration file must exist. Let's create one.\n\n >>> write(join(sample_buildout, 'etc', 'z.cfg'), '')\n >>> print_(system(join('bin', 'buildout')), end='')\n Uninstalling y.cfg.\n Running uninstall recipe.\n Updating foo.\n Installing y.cfg.\n\n >>> print_(open(join(sample_buildout, 'etc', 'z.cfg'), 'r').read())\n \n #[foo_y.cfg DO NOT MODIFY LINES FROM HERE#\n \n [foo]\n a = 1\n b = 2\n \n [log]\n c = 1\n \n #TILL HERE foo_y.cfg]#\n \n\nWhile uninstalling, only the lines that the recipe installed are removed.\n\n >>> print_(system(join('bin', 'buildout')+' buildout:parts='), end='')\n Uninstalling y.cfg.\n Running uninstall recipe.\n Uninstalling foo.\n Running uninstall recipe.\n zc.recipe.deployment: Removing 'PREFIX/etc/foo'\n zc.recipe.deployment: Removing 'PREFIX/etc/cron.d'.\n zc.recipe.deployment: Removing 'PREFIX/etc/init.d'.\n zc.recipe.deployment: Removing 'PREFIX/etc/logrotate.d'.\n zc.recipe.deployment: Removing 'PREFIX/var/cache/foo'.\n zc.recipe.deployment: Removing 'PREFIX/var/lib/foo'.\n zc.recipe.deployment: Removing 'PREFIX/var/log/foo'.\n zc.recipe.deployment: Removing 'PREFIX/var/run/foo'.\n\nBut the files are not deleted.\n\n >>> os.path.exists('y.cfg')\n True\n\n >>> print_(open('y.cfg', 'r').read())\n Some\n existing\n configuration\n Some\n additional\n configuration\n \n\n >>> os.path.exists(join(sample_buildout, 'etc', 'z.cfg'))\n True\n\n >>> print_(open(join(sample_buildout, 'etc', 'z.cfg'), 'r').read())\n \n\n\nEdgecases\n---------\n\nThe SharedConfig recipe checks to see if the current data in the file\nends with a new line. If it doesn't exist it adds one. This is in\naddition to the blank line the recipe adds before the section to enhance\nreadability.\n\n >>> _ = open('anotherconfig.cfg', 'w').write('one')\n >>> write('buildout.cfg',\n ... '''\n ... [buildout]\n ... parts = foo y.cfg\n ...\n ... [foo]\n ... recipe = zc.recipe.deployment\n ... prefix = %s\n ... user = %s\n ... etc-user = %s\n ...\n ... [y.cfg]\n ... recipe = zc.recipe.deployment:sharedconfig\n ... path = anotherconfig.cfg\n ... deployment = foo\n ... text = I predict that there will be a blank line above this.\n ... ''' % (sample_buildout, user, user))\n >>> print_(system(join('bin', 'buildout')), end='')\n Installing foo.\n zc.recipe.deployment:\n Creating 'PREFIX/etc/foo',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/var/cache/foo',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/var/lib/foo',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/var/log/foo',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/var/run/foo',\n mode 750, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/etc/cron.d',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/etc/init.d',\n mode 755, user 'USER', group 'GROUP'\n zc.recipe.deployment:\n Creating 'PREFIX/etc/logrotate.d',\n mode 755, user 'USER', group 'GROUP'\n Installing y.cfg.\n\n >>> print_(open('anotherconfig.cfg').read())\n one\n \n #[foo_y.cfg DO NOT MODIFY LINES FROM HERE#\n I predict that there will be a blank line above this.\n #TILL HERE foo_y.cfg]#\n \n\nBut the recipe doesn't add a new line if there was one already at the end.\n\n >>> _ = open('anotherconfig.cfg', 'w').write('ends with a new line\\n')\n >>> print_(open('anotherconfig.cfg').read())\n ends with a new line\n \n\nWe modify the buildout configuration so that \"install\" is invoked again:\n\n >>> write('buildout.cfg',\n ... '''\n ... [buildout]\n ... parts = foo y.cfg\n ...\n ... [foo]\n ... recipe = zc.recipe.deployment\n ... prefix = %s\n ... user = %s\n ... etc-user = %s\n ...\n ... [y.cfg]\n ... recipe = zc.recipe.deployment:sharedconfig\n ... path = anotherconfig.cfg\n ... deployment = foo\n ... text = there will still be only a single blank line above.\n ... ''' % (sample_buildout, user, user))\n >>> print_(system(join('bin', 'buildout')), end='')\n Uninstalling y.cfg.\n Running uninstall recipe.\n Updating foo.\n Installing y.cfg.\n\n >>> print_(open('anotherconfig.cfg').read())\n ends with a new line\n \n #[foo_y.cfg DO NOT MODIFY LINES FROM HERE#\n there will still be only a single blank line above.\n #TILL HERE foo_y.cfg]#\n \n\nIf we uninstall the file, the data will be the same as \"original_data\":\n\n >>> print_(system(join('bin', 'buildout')+' buildout:parts='), end='')\n Uninstalling y.cfg.\n Running uninstall recipe.\n Uninstalling foo.\n Running uninstall recipe.\n zc.recipe.deployment: Removing 'PREFIX/etc/foo'\n zc.recipe.deployment: Removing 'PREFIX/etc/cron.d'.\n zc.recipe.deployment: Removing 'PREFIX/etc/init.d'.\n zc.recipe.deployment: Removing 'PREFIX/etc/logrotate.d'.\n zc.recipe.deployment: Removing 'PREFIX/var/cache/foo'.\n zc.recipe.deployment: Removing 'PREFIX/var/lib/foo'.\n zc.recipe.deployment: Removing 'PREFIX/var/log/foo'.\n zc.recipe.deployment: Removing 'PREFIX/var/run/foo'.\n\n >>> print_(open('anotherconfig.cfg').read())\n ends with a new line\n \n\nDownload\n**********************", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "http://www.python.org/pypi/zc.recipe.deployment", "keywords": "deployment build", "license": "ZPL 2.1", "maintainer": null, "maintainer_email": null, "name": "zc.recipe.deployment", "package_url": "https://pypi.org/project/zc.recipe.deployment/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/zc.recipe.deployment/", "project_urls": { "Download": "UNKNOWN", "Homepage": "http://www.python.org/pypi/zc.recipe.deployment" }, "release_url": "https://pypi.org/project/zc.recipe.deployment/1.3.0/", "requires_dist": null, "requires_python": null, "summary": "ZC Buildout recipe for Unix deployments", "version": "1.3.0" }, "last_serial": 1812125, "releases": { "0.10.0": [ { "comment_text": "", "digests": { "md5": "75c48930cc42244d51e8ddda86f2a936", "sha256": "fe757e45574c7104854f45bc52cb67b58ff4f20aa9329538bcd2f31e8407f135" }, "downloads": -1, "filename": "zc.recipe.deployment-0.10.0.tar.gz", "has_sig": false, "md5_digest": "75c48930cc42244d51e8ddda86f2a936", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 25167, "upload_time": "2013-03-28T17:36:57", "url": "https://files.pythonhosted.org/packages/b5/e2/315dcca051dbbaefe78ba9162e07c571ab9d23bde5ba9f962b645c642991/zc.recipe.deployment-0.10.0.tar.gz" } ], "0.10.1": [ { "comment_text": "", "digests": { "md5": "e225a93edd7d909115ef50b2ba32391d", "sha256": "20f1540bb62ccb34bbf037962477ec3d275462061e55048d4026943a4febe34c" }, "downloads": -1, "filename": "zc.recipe.deployment-0.10.1.tar.gz", "has_sig": false, "md5_digest": "e225a93edd7d909115ef50b2ba32391d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17778, "upload_time": "2013-04-10T21:17:41", "url": "https://files.pythonhosted.org/packages/ec/4e/831259ced593a1af3c235872e7679dfcb2668577bf032586181929d43c42/zc.recipe.deployment-0.10.1.tar.gz" } ], "0.10.2": [ { "comment_text": "", "digests": { "md5": "41ea073120b733f54575cda63af647e1", "sha256": "d646786d1574e32a5dad10076d44001fe9ea68bde0a6371172b7073ae1b920b6" }, "downloads": -1, "filename": "zc.recipe.deployment-0.10.2.zip", "has_sig": false, "md5_digest": "41ea073120b733f54575cda63af647e1", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 32652, "upload_time": "2013-04-11T01:57:50", "url": "https://files.pythonhosted.org/packages/75/a0/a082d4421d93f2b0fab3256800eff0d2aa738e5a12ac962e952e921d7fb7/zc.recipe.deployment-0.10.2.zip" } ], "0.2": [ { "comment_text": "", "digests": { "md5": "b4dc59799e818196f5104e25da93722d", "sha256": "50e16688cba30209019a9180ddf52d151910a7f791e0dc29a76cc3aa07fe4a44" }, "downloads": -1, "filename": "zc.recipe.deployment-0.2.tar.gz", "has_sig": false, "md5_digest": "b4dc59799e818196f5104e25da93722d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5139, "upload_time": "2007-02-07T12:34:40", "url": "https://files.pythonhosted.org/packages/d4/9f/a1338296904d6a6754fcf5b205cd007f1a415b64f7cddf06dea993d2249c/zc.recipe.deployment-0.2.tar.gz" } ], "0.2.1": [ { "comment_text": "", "digests": { "md5": "2a239621eaddc724ed20df3e7ca41024", "sha256": "754e168a0794ea5f9a02caeaace6c34748a82a5c7aea3b16d019b08e1a4f65c4" }, "downloads": -1, "filename": "zc.recipe.deployment-0.2.1.tar.gz", "has_sig": false, "md5_digest": "2a239621eaddc724ed20df3e7ca41024", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5156, "upload_time": "2007-02-13T17:02:47", "url": "https://files.pythonhosted.org/packages/ce/b5/5e2cec2060f159b297f4a0119df13f350cf2832b52db4319c4366affdc65/zc.recipe.deployment-0.2.1.tar.gz" } ], "0.3": [ { "comment_text": "", "digests": { "md5": "a6420ad96251e38e1a22e456828bd790", "sha256": "9a909b8782bab3fb6be1fd37d6b9414a3501f04f74969967610099d9d74d89a4" }, "downloads": -1, "filename": "zc.recipe.deployment-0.3.tar.gz", "has_sig": false, "md5_digest": "a6420ad96251e38e1a22e456828bd790", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6101, "upload_time": "2007-02-14T21:50:01", "url": "https://files.pythonhosted.org/packages/ee/39/23a6864fb2146170ce04dafc41a54f911a97ba8850557ae73641e9d64acb/zc.recipe.deployment-0.3.tar.gz" } ], "0.4": [ { "comment_text": "", "digests": { "md5": "1f19a88c3a159195c179c7af206f442c", "sha256": "54c883cc1f466cd8a750c2babcb2e3471d625a662db22d9246dda3fbf0b21c2c" }, "downloads": -1, "filename": "zc.recipe.deployment-0.4.tar.gz", "has_sig": false, "md5_digest": "1f19a88c3a159195c179c7af206f442c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6229, "upload_time": "2007-03-22T14:31:51", "url": "https://files.pythonhosted.org/packages/ec/0e/1633d261bd4f76f25104b46644a6638a69bebecb2f75628166dfb8835587/zc.recipe.deployment-0.4.tar.gz" } ], "0.5": [ { "comment_text": "", "digests": { "md5": "735f3cbe832ea1028601dd0fa27dbb6a", "sha256": "3b0caa0aa24221189fc4937d9b88398dcba5bdc4576d0bb788efda527b5a22bb" }, "downloads": -1, "filename": "zc.recipe.deployment-0.5.tar.gz", "has_sig": false, "md5_digest": "735f3cbe832ea1028601dd0fa27dbb6a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6630, "upload_time": "2007-03-23T16:42:33", "url": "https://files.pythonhosted.org/packages/f1/7b/12a8cd17858430a8a1ff34434dbe43e832276033003e34ba5698d6a2c29b/zc.recipe.deployment-0.5.tar.gz" } ], "0.6.0": [ { "comment_text": "", "digests": { "md5": "214b5d20c5ef0965f42b2638f05cdb37", "sha256": "e0ba6bbae146d7684d883f8778b5f46e01cc9bcd73bb2d4050783cdae4fbf9a3" }, "downloads": -1, "filename": "zc.recipe.deployment-0.6.0.tar.gz", "has_sig": false, "md5_digest": "214b5d20c5ef0965f42b2638f05cdb37", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8920, "upload_time": "2008-02-01T15:08:24", "url": "https://files.pythonhosted.org/packages/3d/63/3e44a1d7be6869a79eb286cfa51a9a7206b8f2b4c7cd18c9a23e92036526/zc.recipe.deployment-0.6.0.tar.gz" } ], "0.7.0": [ { "comment_text": "", "digests": { "md5": "d8b14571292347e1d516b65e3c4f617d", "sha256": "08fe0c84fea55e214fbf0ae53773e6975b2a7c099cf5816857adb67896aa7fb8" }, "downloads": -1, "filename": "zc.recipe.deployment-0.7.0.tar.gz", "has_sig": false, "md5_digest": "d8b14571292347e1d516b65e3c4f617d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9306, "upload_time": "2010-02-02T00:11:18", "url": "https://files.pythonhosted.org/packages/cc/6d/1bcaec211d0fcf5801f71244d934446d00cc627efe640d64e8229bd1623e/zc.recipe.deployment-0.7.0.tar.gz" } ], "0.7.1": [ { "comment_text": "", "digests": { "md5": "9312ef02b45ea50103c6b41d1bde315f", "sha256": "89d742e57db412aa0e5924f2f53acf7cfd6cec9a08bb3db72f8cfab7f442f435" }, "downloads": -1, "filename": "zc.recipe.deployment-0.7.1.tar.gz", "has_sig": false, "md5_digest": "9312ef02b45ea50103c6b41d1bde315f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9609, "upload_time": "2010-03-05T21:26:41", "url": "https://files.pythonhosted.org/packages/f4/76/f8708731e24830491379ad6b402a94279f6024b3482c895f4dacc28d404c/zc.recipe.deployment-0.7.1.tar.gz" } ], "0.8.0": [ { "comment_text": "", "digests": { "md5": "b2aa95c87069f94f7f433164a56018dd", "sha256": "860c51dd230bc3e0f0e3d45149e6e0b6a5b9a425361b20e99332b132c7880c2f" }, "downloads": -1, "filename": "zc.recipe.deployment-0.8.0.tar.gz", "has_sig": false, "md5_digest": "b2aa95c87069f94f7f433164a56018dd", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16919, "upload_time": "2010-05-18T17:03:27", "url": "https://files.pythonhosted.org/packages/61/6f/90274309a8b04068035f18d48e3a247dcf02ef9618c26a2ef24aa6c9ddf5/zc.recipe.deployment-0.8.0.tar.gz" } ], "0.9.0": [ { "comment_text": "", "digests": { "md5": "ae4d2c82183049bf3980a12b2f749479", "sha256": "3670da6346a9dff07ae10b8150001370c410f303dc797fd4bf2575c775dc6558" }, "downloads": -1, "filename": "zc.recipe.deployment-0.9.0.tar.gz", "has_sig": false, "md5_digest": "ae4d2c82183049bf3980a12b2f749479", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 19145, "upload_time": "2011-11-21T21:52:59", "url": "https://files.pythonhosted.org/packages/08/86/96f595225110d0d79e8fbf751de078bd7e7d7456f6e28885ec0315baa0d0/zc.recipe.deployment-0.9.0.tar.gz" } ], "1.0.0": [ { "comment_text": "", "digests": { "md5": "ec845fea25de6b5488be76ea26a7f04b", "sha256": "0f95950b57364f5bb0ba300d02dcb82ed2703fbfdf0b10c35309c9c6fc14fc02" }, "downloads": -1, "filename": "zc.recipe.deployment-1.0.0.tar.gz", "has_sig": false, "md5_digest": "ec845fea25de6b5488be76ea26a7f04b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 26738, "upload_time": "2013-04-24T21:27:25", "url": "https://files.pythonhosted.org/packages/a6/40/69dcb9954c45ede80eec63980b5cc13a50679b7f5e2e7fef1f323720e1ee/zc.recipe.deployment-1.0.0.tar.gz" } ], "1.1.0": [ { "comment_text": "", "digests": { "md5": "3a4396e0376d4e1dc4864f61191e85e1", "sha256": "92717fc11b79255cc0f847de98c9af7ca2a5c2cbc1b8541335288cf72bb761a5" }, "downloads": -1, "filename": "zc.recipe.deployment-1.1.0.tar.gz", "has_sig": false, "md5_digest": "3a4396e0376d4e1dc4864f61191e85e1", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 27554, "upload_time": "2013-11-05T17:54:20", "url": "https://files.pythonhosted.org/packages/e6/84/4532a4ee4b4c7f99151be81c792c340d1a55acba8848bff255bf2047c3c4/zc.recipe.deployment-1.1.0.tar.gz" } ], "1.2.0": [ { "comment_text": "", "digests": { "md5": "111b63423379ffdd4da6a74bf7a1a61d", "sha256": "8289e6ecf95c735b6cb7ede0574dcc54eefd942b676fb8e0c85832ca8f0584f2" }, "downloads": -1, "filename": "zc.recipe.deployment-1.2.0.tar.gz", "has_sig": false, "md5_digest": "111b63423379ffdd4da6a74bf7a1a61d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 28610, "upload_time": "2014-02-04T23:17:33", "url": "https://files.pythonhosted.org/packages/cc/53/1f30eaf45477c2669efb1faf6ddb5ceb857f914fba0c9aa5ddf7dcd43516/zc.recipe.deployment-1.2.0.tar.gz" } ], "1.3.0": [ { "comment_text": "", "digests": { "md5": "f243035cba7f79489a9dc6503c3e8175", "sha256": "003f7ef6c099cfdd9c4f11b00ec03343bd4ded947f131e8c666d0be966a59803" }, "downloads": -1, "filename": "zc.recipe.deployment-1.3.0.tar.gz", "has_sig": false, "md5_digest": "f243035cba7f79489a9dc6503c3e8175", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 29211, "upload_time": "2015-11-11T20:31:51", "url": "https://files.pythonhosted.org/packages/25/26/da074f8f52034aa81a5c1cbfcedf495d376be4ec02b417cb06414a3aad68/zc.recipe.deployment-1.3.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "f243035cba7f79489a9dc6503c3e8175", "sha256": "003f7ef6c099cfdd9c4f11b00ec03343bd4ded947f131e8c666d0be966a59803" }, "downloads": -1, "filename": "zc.recipe.deployment-1.3.0.tar.gz", "has_sig": false, "md5_digest": "f243035cba7f79489a9dc6503c3e8175", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 29211, "upload_time": "2015-11-11T20:31:51", "url": "https://files.pythonhosted.org/packages/25/26/da074f8f52034aa81a5c1cbfcedf495d376be4ec02b417cb06414a3aad68/zc.recipe.deployment-1.3.0.tar.gz" } ] }