[Checkins] SVN: z3c.recipe.filetemplate/branches/gary-powertools/ add remaining tests, license, change docs. change behavior of ``files`` with directories when ``source-directory`` is used.
Gary Poster
gary at modernsongs.com
Thu Apr 30 13:40:34 EDT 2009
Log message for revision 99621:
add remaining tests, license, change docs. change behavior of ``files`` with directories when ``source-directory`` is used.
Changed:
U z3c.recipe.filetemplate/branches/gary-powertools/CHANGES.txt
A z3c.recipe.filetemplate/branches/gary-powertools/LICENSE.txt
U z3c.recipe.filetemplate/branches/gary-powertools/setup.py
U z3c.recipe.filetemplate/branches/gary-powertools/z3c/recipe/filetemplate/README.txt
U z3c.recipe.filetemplate/branches/gary-powertools/z3c/recipe/filetemplate/__init__.py
U z3c.recipe.filetemplate/branches/gary-powertools/z3c/recipe/filetemplate/tests.py
U z3c.recipe.filetemplate/branches/gary-powertools/z3c/recipe/filetemplate/tests.txt
-=-
Modified: z3c.recipe.filetemplate/branches/gary-powertools/CHANGES.txt
===================================================================
--- z3c.recipe.filetemplate/branches/gary-powertools/CHANGES.txt 2009-04-30 16:27:23 UTC (rev 99620)
+++ z3c.recipe.filetemplate/branches/gary-powertools/CHANGES.txt 2009-04-30 17:40:33 UTC (rev 99621)
@@ -1,11 +1,33 @@
Changes
=======
-1.1 (unreleased)
+2.0 (2009-04-30)
----------------
-...
+- FEATURE: Store your template files in a separate directory structure, using
+ the ``source-directory`` option.
+- FEATURE: Specify multiple files automatically with globs.
+
+- FEATURE: Templates can reference other buildout sections using the usual
+ syntax, e.g. ${buildout:parts}
+
+- FEATURE: Share options with other sections using the typical ``extends``
+ option.
+
+- FEATURE: Create destination directories automatically.
+
+- FEATURE: Define option values for templates dynamically in Python with the
+ ``interpreted-options`` option.
+
+- FEATURE: Get paths for eggs by specifying ``eggs`` and ``extra-paths``, just
+ like zc.recipe.egg script recipe. These are available in template options
+ in colon-delimited, space-delimited, and quoted variants. You can also build
+ your own using the ``interpreted-options`` feature.
+
+- BUGFIX: templates are not processed if there are no changes to them or the
+ buildout.
+
1.0 (2007-09-30)
----------------
Added: z3c.recipe.filetemplate/branches/gary-powertools/LICENSE.txt
===================================================================
--- z3c.recipe.filetemplate/branches/gary-powertools/LICENSE.txt (rev 0)
+++ z3c.recipe.filetemplate/branches/gary-powertools/LICENSE.txt 2009-04-30 17:40:33 UTC (rev 99621)
@@ -0,0 +1,54 @@
+Zope Public License (ZPL) Version 2.1
+-------------------------------------
+
+A copyright notice accompanies this license document that
+identifies the copyright holders.
+
+This license has been certified as open source. It has also
+been designated as GPL compatible by the Free Software
+Foundation (FSF).
+
+Redistribution and use in source and binary forms, with or
+without modification, are permitted provided that the
+following conditions are met:
+
+1. Redistributions in source code must retain the
+ accompanying copyright notice, this list of conditions,
+ and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the accompanying
+ copyright notice, this list of conditions, and the
+ following disclaimer in the documentation and/or other
+ materials provided with the distribution.
+
+3. Names of the copyright holders must not be used to
+ endorse or promote products derived from this software
+ without prior written permission from the copyright
+ holders.
+
+4. The right to distribute this software or to use it for
+ any purpose does not give you the right to use
+ Servicemarks (sm) or Trademarks (tm) of the copyright
+ holders. Use of them is covered by separate agreement
+ with the copyright holders.
+
+5. If any files are modified, you must cause the modified
+ files to carry prominent notices stating that you changed
+ the files and the date of any change.
+
+Disclaimer
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS''
+ AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ NO EVENT SHALL THE COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGE.
\ No newline at end of file
Property changes on: z3c.recipe.filetemplate/branches/gary-powertools/LICENSE.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Modified: z3c.recipe.filetemplate/branches/gary-powertools/setup.py
===================================================================
--- z3c.recipe.filetemplate/branches/gary-powertools/setup.py 2009-04-30 16:27:23 UTC (rev 99620)
+++ z3c.recipe.filetemplate/branches/gary-powertools/setup.py 2009-04-30 17:40:33 UTC (rev 99621)
@@ -1,3 +1,17 @@
+##############################################################################
+#
+# Copyright (c) 2007-2009 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
@@ -5,12 +19,14 @@
return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
setup(name='z3c.recipe.filetemplate',
- version = '1.1dev',
+ version = '2.0',
license='ZPL 2.1',
url='http://pypi.python.org/pypi/z3c.recipe.filetemplate',
description="zc.buildout recipe for creating files from file templates",
author='Philipp von Weitershausen',
author_email='philipp at weitershausen.de',
+ maintainer='Gary Poster',
+ maintainer_email='gary.poster at canonical.com',
long_description=(read('z3c', 'recipe', 'filetemplate', 'README.txt')
+ '\n\n' +
read('CHANGES.txt')),
Modified: z3c.recipe.filetemplate/branches/gary-powertools/z3c/recipe/filetemplate/README.txt
===================================================================
--- z3c.recipe.filetemplate/branches/gary-powertools/z3c/recipe/filetemplate/README.txt 2009-04-30 16:27:23 UTC (rev 99620)
+++ z3c.recipe.filetemplate/branches/gary-powertools/z3c/recipe/filetemplate/README.txt 2009-04-30 17:40:33 UTC (rev 99621)
@@ -70,8 +70,9 @@
you don't want to clutter up the destination folder, you can add a prefix to
the source folder. Here is an example.
-Note that, for the destination, intermediate folders are created if they do not
-exist.
+First, we specify a ``source-directory`` in the buildout. You can specify
+``files`` as a filter if desired, but by default it will find any file (ending
+with ".in").
>>> write(sample_buildout, 'buildout.cfg',
... """
@@ -83,6 +84,10 @@
... source-directory = template
... world = Philipp
... """)
+
+Now we'll make a "template" directory, as listed in the buildout configuration
+above, and populate it for our example.
+
>>> mkdir(sample_buildout, 'template')
>>> mkdir(sample_buildout, 'template', 'etc')
>>> mkdir(sample_buildout, 'template', 'bin')
@@ -98,6 +103,11 @@
... os.path.join(
... sample_buildout, 'template', 'bin', 'helloworld.sh.in'),
... 0711)
+
+Notice that, before running buildout, the ``helloworld.txt`` file is still
+around, we don't have an etc directory, and the bin directory doesn't have our
+``helloworld.sh``.
+
>>> ls(sample_buildout)
- .installed.cfg
d bin
@@ -110,6 +120,11 @@
d template
>>> ls(sample_buildout, 'bin')
- buildout
+
+Now we install. The old "helloworld.txt" is gone, and we now see etc. Note
+that, for the destination, intermediate folders are created if they do not
+exist.
+
>>> print system(buildout)
Uninstalling message.
Installing message.
@@ -123,6 +138,9 @@
- helloworld.txt.in
d parts
d template
+
+The files exist and have the content we expect.
+
>>> ls(sample_buildout, 'bin')
- buildout
- helloworld.sh
@@ -136,11 +154,48 @@
>>> cat(sample_buildout, 'etc', 'helloworld.conf')
Hello Philipp from the etc dir!
+If you use the ``files`` option along with ``source-directory``, it becomes a
+filter. Every target file must match at least one of the names in ``files``.
+Therefore, if we only build .sh files, the etc directory will disappear.
+
+ >>> write(sample_buildout, 'buildout.cfg',
+ ... """
+ ... [buildout]
+ ... parts = message
+ ...
+ ... [message]
+ ... recipe = z3c.recipe.filetemplate
+ ... source-directory = template
+ ... files = *.sh
+ ... world = Philipp
+ ... """)
+
+ >>> print system(buildout)
+ Uninstalling message.
+ Installing message.
+ >>> ls(sample_buildout)
+ - .installed.cfg
+ d bin
+ - buildout.cfg
+ d develop-eggs
+ d eggs
+ - helloworld.txt.in
+ d parts
+ d template
+
+ >>> ls(sample_buildout, 'bin')
+ - buildout
+ - helloworld.sh
+
+Also note that, if you use a source directory and your ``files`` specify a
+directory, the directory must match precisely.
+
Substituting from Other Sections
================================
Substitutions can also come from other sections in the buildout, using the
-standard buildout syntax.
+standard buildout syntax, but used in the template. Notice
+``${buildout:parts}`` in the template below.
>>> write(sample_buildout, 'helloworld.txt.in',
... """
@@ -167,8 +222,8 @@
Sharing variables
=================
-The recipe allows extending one or more sections, to decrease repetition. For
-instance, consider the following buildout.
+The recipe allows extending one or more sections, to decrease repetition, using
+the ``extends`` option. For instance, consider the following buildout.
>>> write(sample_buildout, 'buildout.cfg',
... """
@@ -299,16 +354,61 @@
...demo... ...demoneeded... .../sample-buildout/foo
Defining options in Python
-============================
+==========================
-You can specify that certain variables should be interpreted as Python.
+You can specify that certain variables should be interpreted as Python using
+``interpreted-options``. This takes zero or more lines. Each line should
+specify an option. It can define immediately (see ``duplicate-os-paths``,
+``foo-paths``, and ``silly-range`` in the example below) or point to an option
+to be interepreted, which can be useful if you want to define a
+multi-line expression (see ``first-interpreted-option`` and
+``message-reversed-is-egassem``).
-XXX
+ >>> write(sample_buildout, 'buildout.cfg',
+ ... """
+ ... [buildout]
+ ... parts = message
+ ...
+ ... [message]
+ ... recipe = z3c.recipe.filetemplate
+ ... files = helloworld.txt
+ ... eggs = demo<0.3
+ ... interpreted-options = duplicate-os-paths=(os.pathsep).join(paths)
+ ... foo-paths='FOO'.join(all_paths)
+ ... silly-range = repr(range(5))
+ ... first-interpreted-option
+ ... message-reversed-is-egassem
+ ... first-interpreted-option =
+ ... options['interpreted-options'].split()[0].strip()
+ ... message-reversed-is-egassem=
+ ... ''.join(
+ ... reversed(
+ ... buildout['buildout']['parts']))
+ ... not-interpreted=hello world
+ ...
+ ... find-links = %(server)s
+ ... index = %(server)s/index
+ ... """ % dict(server=link_server))
- [buildout]
- parts = message
-
- [message]
- recipe = z3c.recipe.filetemplate
- files = helloworld.txt
- interpreted-options = path-separator=os.pathsep
+ >>> write(sample_buildout, 'helloworld.txt.in',
+ ... """
+ ... ${not-interpreted}!
+ ... duplicate-os-paths: ${duplicate-os-paths}
+ ... foo-paths: ${foo-paths}
+ ... silly-range: ${silly-range}
+ ... first-interpreted-option: ${first-interpreted-option}
+ ... message-reversed-is-egassem: ${message-reversed-is-egassem}
+ ... """)
+
+ >>> print system(buildout)
+ Uninstalling message.
+ Installing message.
+
+ >>> cat(sample_buildout, 'helloworld.txt') # doctest:+ELLIPSIS
+ hello world!
+ duplicate-os-paths: ...demo-0.2...egg:...demoneeded-1.2c1...egg
+ foo-paths: ...demo-0.2...eggFOO...demoneeded-1.2c1...egg
+ silly-range: [0, 1, 2, 3, 4]
+ first-interpreted-option: duplicate-os-paths=(os.pathsep).join(paths)
+ message-reversed-is-egassem: egassem
+
Modified: z3c.recipe.filetemplate/branches/gary-powertools/z3c/recipe/filetemplate/__init__.py
===================================================================
--- z3c.recipe.filetemplate/branches/gary-powertools/z3c/recipe/filetemplate/__init__.py 2009-04-30 16:27:23 UTC (rev 99620)
+++ z3c.recipe.filetemplate/branches/gary-powertools/z3c/recipe/filetemplate/__init__.py 2009-04-30 17:40:33 UTC (rev 99621)
@@ -1,3 +1,17 @@
+##############################################################################
+#
+# Copyright (c) 2007-2009 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 fnmatch
import logging
import os
@@ -5,6 +19,7 @@
import stat
import string
import sys
+import traceback
import zc.recipe.egg
import zc.buildout
import zc.buildout.easy_install
@@ -54,8 +69,8 @@
self.recursive = True
if os.path.isabs(self.source_dir):
self._user_error(ABS_PATH_ERROR, self.source_dir)
- self.source_dir = os.path.normpath(os.path.join(
- here, self.source_dir))
+ self.source_dir = zc.buildout.easy_install.realpath(
+ os.path.normpath(os.path.join(here, self.source_dir)))
if not self.source_dir.startswith(here):
self._user_error(
'source-directory must be within the buildout directory')
@@ -67,19 +82,12 @@
for filename in self.filenames:
if os.path.isabs(filename):
self._user_error(ABS_PATH_ERROR, filename)
- if self.source_dir:
- if '/' in filename:
- self._user_error(
- 'Slashes cannot be in file names when a source '
- 'directory is used: %s.',
- filename)
- else:
- if not os.path.normpath(
- os.path.join(self.source_dir, filename)
- ).startswith(self.source_dir):
- # path used ../ to get out of buildout dir
- self._user_error(
- 'source files must be within the buildout directory')
+ if not zc.buildout.easy_install.realpath(
+ os.path.normpath(os.path.join(self.source_dir, filename))
+ ).startswith(self.source_dir):
+ # path used ../ to get out of buildout dir
+ self._user_error(
+ 'source files must be within the buildout directory')
source_patterns.append('%s.in' % filename)
unmatched = set(source_patterns)
unexpected_dirs = []
@@ -98,11 +106,19 @@
file_info[name] = (
val, last_modified, statinfo.st_mode)
found = set()
- for pattern in source_patterns:
- # val is relative to
+ for orig_pattern in source_patterns:
+ parts = orig_pattern.split('/')
+ dir = os.path.sep.join(parts[:-1])
+ pattern = parts[-1]
+ if (dir and
+ relative_prefix != dir and
+ dir != '.' and relative_prefix != ''):
+ # if a directory is specified, it must match
+ # precisely. We also support the '.' directory.
+ continue
matching = fnmatch.filter(file_info, pattern)
if matching:
- unmatched.discard(pattern)
+ unmatched.discard(orig_pattern)
found.update(matching)
for name in found:
self.actions.append(file_info[name])
@@ -110,7 +126,8 @@
self.source_dir, visit, None)
else:
for val in source_patterns:
- source = os.path.join(self.source_dir, val)
+ source = zc.buildout.easy_install.realpath(
+ os.path.join(self.source_dir, val))
if os.path.exists(source):
unmatched.discard(val)
statinfo = os.stat(source)
@@ -131,15 +148,37 @@
self._user_error(
'No template found for these file names: %s',
', '.join(unmatched))
+ # parse interpreted options
interpreted = self.options.get('interpreted-options')
if interpreted:
globs = {'__builtins__': __builtins__, 'os': os, 'sys': sys}
locs = {'name': name, 'options': options, 'buildout': buildout,
'paths': paths, 'all_paths': all_paths}
- for value in interpreted.split():
+ for value in interpreted.split('\n'):
if value:
- key, expression = value.split('=', 1)
- options[key] = str(eval(expression, globs, locs))
+ value = value.split('=', 1)
+ key = value[0].strip()
+ if len(value) == 1:
+ try:
+ expression = options[key]
+ except KeyError:
+ self._user_error(
+ 'Expression for key not found: %s', key)
+ else:
+ expression = value[1]
+ try:
+ evaluated = eval(expression, globs, locs)
+ except:
+ self._user_error(
+ 'Error when evaluating %r expression %r:\n%s',
+ key, expression, traceback.format_exc())
+ if not isinstance(evaluated, basestring):
+ self._user_error(
+ 'Result of evaluating Python expression must be a '
+ 'string. The result of %r expression %r was %r, '
+ 'a %s.',
+ key, expression, evaluated, type(evaluated))
+ options[key] = evaluated
def _user_error(self, msg, *args):
msg = msg % args
self.logger.error(msg)
Modified: z3c.recipe.filetemplate/branches/gary-powertools/z3c/recipe/filetemplate/tests.py
===================================================================
--- z3c.recipe.filetemplate/branches/gary-powertools/z3c/recipe/filetemplate/tests.py 2009-04-30 16:27:23 UTC (rev 99620)
+++ z3c.recipe.filetemplate/branches/gary-powertools/z3c/recipe/filetemplate/tests.py 2009-04-30 17:40:33 UTC (rev 99621)
@@ -1,3 +1,17 @@
+##############################################################################
+#
+# Copyright (c) 2007-2009 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 zc.buildout.testing
import zc.buildout.tests
from zope.testing import doctest
Modified: z3c.recipe.filetemplate/branches/gary-powertools/z3c/recipe/filetemplate/tests.txt
===================================================================
--- z3c.recipe.filetemplate/branches/gary-powertools/z3c/recipe/filetemplate/tests.txt 2009-04-30 16:27:23 UTC (rev 99620)
+++ z3c.recipe.filetemplate/branches/gary-powertools/z3c/recipe/filetemplate/tests.txt 2009-04-30 17:40:33 UTC (rev 99621)
@@ -10,35 +10,35 @@
The recipe can subsitute the same set of variables on several files at
the same time:
- >>> write(sample_buildout, 'helloworld.txt.in',
- ... """
- ... Hello ${world}!
- ... """)
+ >>> write(sample_buildout, 'helloworld.txt.in',
+ ... """
+ ... Hello ${world}!
+ ... """)
+
+ >>> write(sample_buildout, 'goodbyeworld.txt.in',
+ ... """
+ ... Goodbye ${world}!
+ ... """)
- >>> write(sample_buildout, 'goodbyeworld.txt.in',
- ... """
- ... Goodbye ${world}!
- ... """)
-
File names are separated by any kind of whitespace:
- >>> write(sample_buildout, 'buildout.cfg',
- ... """
- ... [buildout]
- ... parts = multiple
- ...
- ... [multiple]
- ... recipe = z3c.recipe.filetemplate
- ... files = helloworld.txt
- ... goodbyeworld.txt
- ... world = Philipp
- ... """)
+ >>> write(sample_buildout, 'buildout.cfg',
+ ... """
+ ... [buildout]
+ ... parts = multiple
+ ...
+ ... [multiple]
+ ... recipe = z3c.recipe.filetemplate
+ ... files = helloworld.txt
+ ... goodbyeworld.txt
+ ... world = Philipp
+ ... """)
After executing buildout, we can see that ``$world`` has indeed been
replaced by ``Philipp``:
- >>> print system(buildout)
- Installing multiple.
+ >>> print system(buildout)
+ Installing multiple.
Absolute paths
--------------
@@ -46,115 +46,266 @@
The recipe only accepts relative file paths. For example, consider
this invalid buildout configuration:
- >>> write(sample_buildout, 'buildout.cfg',
- ... """
- ... [buildout]
- ... parts = evil
- ...
- ... [evil]
- ... recipe = z3c.recipe.filetemplate
- ... files = /etc/passwd.in
- ... root = me
- ... """)
+ >>> write(sample_buildout, 'buildout.cfg',
+ ... """
+ ... [buildout]
+ ... parts = evil
+ ...
+ ... [evil]
+ ... recipe = z3c.recipe.filetemplate
+ ... files = /etc/passwd.in
+ ... root = me
+ ... """)
+
+ >>> print system(buildout)
+ evil: /etc/passwd.in is an absolute path. Paths must be relative to the buildout directory.
+ While:
+ Installing.
+ Getting section evil.
+ Initializing part evil.
+ Error: /etc/passwd.in is an absolute path. Paths must be relative to the buildout directory.
- >>> print system(buildout)
- evil: /etc/passwd.in is an absolute path. Paths must be relative to the buildout directory.
- While:
- Installing.
- Getting section evil.
- Initializing part evil.
- Error: /etc/passwd.in is an absolute path. Paths must be relative to the buildout directory.
-
-
Missing template
----------------
The recipe will also complain with an error if you specify a file name
for which no template can be found:
- >>> write(sample_buildout, 'buildout.cfg',
- ... """
- ... [buildout]
- ... parts = notthere
- ...
- ... [notthere]
- ... recipe = z3c.recipe.filetemplate
- ... files = doesntexist
- ... """)
+ >>> write(sample_buildout, 'buildout.cfg',
+ ... """
+ ... [buildout]
+ ... parts = notthere
+ ...
+ ... [notthere]
+ ... recipe = z3c.recipe.filetemplate
+ ... files = doesntexist
+ ... """)
+
+ >>> print system(buildout)
+ notthere: No template found for these file names: doesntexist.in
+ While:
+ Installing.
+ Getting section notthere.
+ Initializing part notthere.
+ Error: No template found for these file names: doesntexist.in
- >>> print system(buildout)
- notthere: No template found for these file names: doesntexist.in
- While:
- Installing.
- Getting section notthere.
- Initializing part notthere.
- Error: No template found for these file names: doesntexist.in
-
-
-
Already existing file
---------------------
Another case where the recipe will complain is when you're trying to
replace a file that's already there:
- >>> write(sample_buildout, 'alreadyhere.txt',
- ... """
- ... I'm already here
- ... """)
+ >>> write(sample_buildout, 'alreadyhere.txt',
+ ... """
+ ... I'm already here
+ ... """)
+
+ >>> write(sample_buildout, 'alreadyhere.txt.in',
+ ... """
+ ... I'm the template that's supposed to replace the file above.
+ ... """)
+
+ >>> write(sample_buildout, 'buildout.cfg',
+ ... """
+ ... [buildout]
+ ... parts = alreadythere
+ ...
+ ... [alreadythere]
+ ... recipe = z3c.recipe.filetemplate
+ ... files = alreadyhere.txt
+ ... """)
- >>> write(sample_buildout, 'alreadyhere.txt.in',
- ... """
- ... I'm the template that's supposed to replace the file above.
- ... """)
-
- >>> write(sample_buildout, 'buildout.cfg',
- ... """
- ... [buildout]
- ... parts = alreadythere
- ...
- ... [alreadythere]
- ... recipe = z3c.recipe.filetemplate
- ... files = alreadyhere.txt
- ... """)
-
- >>> print system(buildout)
- Uninstalling multiple.
- Installing alreadythere.
- alreadythere: Destinations already exist: alreadyhere.txt.in. Please make
- sure that you really want to generate these automatically.
- Then move them away.
- While:
+ >>> print system(buildout)
+ Uninstalling multiple.
Installing alreadythere.
- Error: Destinations already exist: alreadyhere.txt.in. Please make sure
- that you really want to generate these automatically. Then move
- them away.
+ alreadythere: Destinations already exist: alreadyhere.txt.in. Please make
+ sure that you really want to generate these automatically.
+ Then move them away.
+ While:
+ Installing alreadythere.
+ Error: Destinations already exist: alreadyhere.txt.in. Please make sure
+ that you really want to generate these automatically. Then move
+ them away.
-
Missing variables
-----------------
The recipe will also fail to execute if a template refers to variables
that aren't defined in ``buildout.cfg``:
- >>> write(sample_buildout, 'missing.txt.in',
- ... """
- ... Hello ${world}!
- ... """)
+ >>> write(sample_buildout, 'missing.txt.in',
+ ... """
+ ... Hello ${world}!
+ ... """)
+
+ >>> write(sample_buildout, 'buildout.cfg',
+ ... """
+ ... [buildout]
+ ... parts = missing
+ ...
+ ... [missing]
+ ... recipe = z3c.recipe.filetemplate
+ ... files = missing.txt
+ ... """)
+
+ >>> print system(buildout)
+ Installing missing.
+ While:
+ Installing missing.
+ Error: Referenced option does not exist: missing world
- >>> write(sample_buildout, 'buildout.cfg',
- ... """
- ... [buildout]
- ... parts = missing
- ...
- ... [missing]
- ... recipe = z3c.recipe.filetemplate
- ... files = missing.txt
- ... """)
+No changes means just an update
+-------------------------------
- >>> print system(buildout)
- Installing missing.
- While:
- Installing missing.
- Error: Referenced option does not exist: missing world
+If there are no changes in the buildout section, or in the files it will build,
+the recipe will update, which is a no-op.
+ >>> write(sample_buildout, 'buildout.cfg',
+ ... """
+ ... [buildout]
+ ... parts = message
+ ...
+ ... [message]
+ ... recipe = z3c.recipe.filetemplate
+ ... files = helloworld.txt
+ ... world = Philipp
+ ... """)
+
+ >>> print system(buildout)
+ Installing message.
+ >>> print system(buildout)
+ Updating message.
+
+Changes in a source directory cause a re-install
+------------------------------------------------
+
+The recipe keeps track of what files were installed, and so adding and removing
+files causes a reinstall with the expected behavior.
+
+ >>> write(sample_buildout, 'buildout.cfg',
+ ... """
+ ... [buildout]
+ ... parts = message
+ ...
+ ... [message]
+ ... recipe = z3c.recipe.filetemplate
+ ... source-directory = template
+ ... world = Philipp
+ ... """)
+ >>> mkdir(sample_buildout, 'template')
+ >>> mkdir(sample_buildout, 'template', 'etc')
+ >>> write(sample_buildout, 'template', 'etc', 'helloworld.sh.in',
+ ... """
+ ... Hello ${world} from the .sh file!
+ ... """)
+ >>> print system(buildout)
+ Uninstalling message.
+ Installing message.
+ >>> ls(sample_buildout, 'etc')
+ - helloworld.sh
+ >>> write(sample_buildout, 'template', 'etc', 'helloworld.conf.in',
+ ... """
+ ... Hello ${world} from the etc dir!
+ ... """)
+ >>> print system(buildout)
+ Uninstalling message.
+ Installing message.
+ >>> ls(sample_buildout, 'etc')
+ - helloworld.conf
+ - helloworld.sh
+ >>> remove(sample_buildout, 'template', 'etc', 'helloworld.sh.in')
+ >>> print system(buildout)
+ Uninstalling message.
+ Installing message.
+ >>> ls(sample_buildout, 'etc')
+ - helloworld.conf
+
+The main README also has an example of modifying a file, which will also cause
+a reinstall.
+
+More than one file in ``files`` with ``source-directory``
+---------------------------------------------------------
+
+When using ``source-directory``, ``files`` is a glob-based filter. This is
+shown in the main README. What is not shown is that you can have more than
+one ``files`` filter. Here's an example.
+
+ >>> write(sample_buildout, 'template', 'etc', 'helloworld.sh.in',
+ ... """
+ ... Hello ${world} from the .sh file!
+ ... """)
+ >>> write(sample_buildout, 'template', 'etc', 'helloworld.cfg.in',
+ ... """
+ ... Hello ${world} from the .cfg file!
+ ... """)
+
+ >>> write(sample_buildout, 'buildout.cfg',
+ ... """
+ ... [buildout]
+ ... parts = message
+ ...
+ ... [message]
+ ... recipe = z3c.recipe.filetemplate
+ ... source-directory = template
+ ... files = *.conf
+ ... helloworld.cfg
+ ... world = Philipp
+ ... """)
+ >>> print system(buildout)
+ Uninstalling message.
+ Installing message.
+ >>> ls(sample_buildout, 'etc')
+ - helloworld.cfg
+ - helloworld.conf
+
+``files`` with a directory when using a ``source-directory``
+------------------------------------------------------------
+
+If you use a source directory and your ``files`` specify a directory, the
+directory must match precisely.
+
+ >>> mkdir(sample_buildout, 'template', 'etc', 'in')
+ >>> write(sample_buildout, 'template', 'etc', 'in', 'helloworld.cfg.in',
+ ... """
+ ... Hello ${world} from the inner .cfg file!
+ ... """)
+ >>> write(sample_buildout, 'buildout.cfg',
+ ... """
+ ... [buildout]
+ ... parts = message
+ ...
+ ... [message]
+ ... recipe = z3c.recipe.filetemplate
+ ... source-directory = template
+ ... files = *.sh
+ ... etc/helloworld.cfg
+ ... world = Philipp
+ ... """)
+ >>> print system(buildout)
+ Uninstalling message.
+ Installing message.
+ >>> ls(sample_buildout, 'etc')
+ - helloworld.cfg
+ - helloworld.sh
+
+ >>> write(sample_buildout, 'buildout.cfg',
+ ... """
+ ... [buildout]
+ ... parts = message
+ ...
+ ... [message]
+ ... recipe = z3c.recipe.filetemplate
+ ... source-directory = template
+ ... files = *.sh
+ ... etc/in/helloworld.cfg
+ ... world = Philipp
+ ... """)
+ >>> print system(buildout)
+ Uninstalling message.
+ Installing message.
+ >>> ls(sample_buildout, 'etc')
+ - helloworld.sh
+ d in
+ >>> ls(sample_buildout, 'etc', 'in')
+ - helloworld.cfg
+
More information about the Checkins
mailing list