Skip to main content

Set of helper recipies for zc.buildout

Project description

Filesystem Buildout Recipe

Creating Directories

>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... parts = data-dir
... find-links = http://download.zope.org/distribution
...
... [data-dir]
... recipe = lovely.recipe:mkdir
... path = ${buildout:directory}/mystuff
... """)
>>> print system(buildout),
Installing data-dir.
data-dir: Creating directory /sample-buildout/mystuff
>>> ls(sample_buildout)
-  .installed.cfg
d  bin
-  buildout.cfg
d  develop-eggs
d  eggs
d  mystuff
d  parts

If we change the directory name the old directory (‘mystuff’) is not deleted.

>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... parts = data-dir
... find-links = http://download.zope.org/distribution
...
... [data-dir]
... recipe = lovely.recipe:mkdir
... path = ${buildout:directory}/otherdir
... """)
>>> print system(buildout),
Uninstalling data-dir.
Installing data-dir.
data-dir: Creating directory /sample-buildout/otherdir
>>> ls(sample_buildout)
-  .installed.cfg
d  bin
-  buildout.cfg
d  develop-eggs
d  eggs
d  mystuff
d  otherdir
d  parts

We can also create a full path.

>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... parts = data-dir
... find-links = http://download.zope.org/distribution
...
... [data-dir]
... recipe = lovely.recipe:mkdir
... path = ${buildout:directory}/with/subdir
... """)
>>> print system(buildout),
Uninstalling data-dir.
Installing data-dir.
data-dir: Cannot create /sample-buildout/with/subdir. /sample-buildout/with is not a directory.
While:
  Installing data-dir.
Error: Invalid Path

But we need to activate this function explicitely.

>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... parts = data-dir
... find-links = http://download.zope.org/distribution
...
... [data-dir]
... recipe = lovely.recipe:mkdir
... createpath = True
... path = ${buildout:directory}/with/subdir
... """)
>>> print system(buildout),
Installing data-dir.
data-dir: Creating parent directory /sample-buildout/with
data-dir: Creating directory /sample-buildout/with/subdir
>>> ls(sample_buildout)
-  .installed.cfg
d  bin
-  buildout.cfg
d  develop-eggs
d  eggs
d  mystuff
d  otherdir
d  parts
d  with
>>> ls(sample_buildout + '/with')
d  subdir

There is no update method so the install method is used upon update and the directories get recreated.

>>> rmdir(sample_buildout + '/with')
>>> print system(buildout),
Updating data-dir.
The recipe for data-dir doesn't define an update method. Using its install method.
data-dir: Creating parent directory /sample-buildout/with
data-dir: Creating directory /sample-buildout/with/subdir

We can change the owner of the created directory if run as root. This is tested in mkdir-root.txt.

If not run as root, setting the owner is an error:

>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... parts = data-dir
... find-links = http://download.zope.org/distribution
...
... [data-dir]
... recipe = lovely.recipe:mkdir
... createpath = True
... path = ${buildout:directory}/another/with/subdir
... owner = nobody
... """)
>>> print system(buildout),
While:
  Installing.
  Getting section data-dir.
  Initializing part data-dir.
Error: Only root can change the owner to nobody.

It is an error when the user does not exist:

>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... parts = data-dir
... find-links = http://download.zope.org/distribution
...
... [data-dir]
... recipe = lovely.recipe:mkdir
... createpath = True
... path = ${buildout:directory}/another/with/subdir
... owner = someuser
... """)
>>> print system(buildout),
While:
  Installing.
  Getting section data-dir.
  Initializing part data-dir.
Error: The user someuser does not exist.

Creating Files

The mkfile recipe creates one or more files with a given path, content and permissions.

Note that the parent directory needs to exist, otherwise a user error is raised.

>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... parts = script
...
... [script]
... recipe = lovely.recipe:mkfile
... path = /x/y/file.sh
... content = hoschi
... mode = 0755
... """)
>>> print system(buildout)
Uninstalling data-dir.
Installing script.
script: Cannot create file /x/y/file.sh. /x/y is not a directory.
While:
  Installing script.
Error: Invalid path
>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... parts = script
...
... [script]
... recipe = lovely.recipe:mkfile
... path = file.sh
... content = hoschi
... mode = 0755
... """)
>>> print system(buildout)
Installing script.
script: Writing file /sample-buildout/file.sh
<BLANKLINE>
>>> ls(sample_buildout)
-  .installed.cfg
d  bin
-  buildout.cfg
d  develop-eggs
d  eggs
-  file.sh
d  mystuff
d  otherdir
d  parts
d  with

The content is written to the file.

>>> cat(sample_buildout, 'file.sh')
hoschi

And the mode is set.

>>> import os, stat
>>> path = os.path.join(sample_buildout, 'file.sh')
>>> oct(stat.S_IMODE(os.stat(path)[stat.ST_MODE]))
'0755'

If we change the filename the old file is deleted.

>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... parts = script
...
... [script]
... recipe = lovely.recipe:mkfile
... path = newfile.sh
... content = hoschi
... mode = 0755
... """)
>>> print system(buildout)
Uninstalling script.
Installing script.
script: Writing file /sample-buildout/newfile.sh
<BLANKLINE>
>>> ls(sample_buildout)
-  .installed.cfg
d  bin
-  buildout.cfg
d  develop-eggs
d  eggs
d  mystuff
-  newfile.sh
d  otherdir
d  parts
d  with

We can also specify to create the path for the file.

>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... parts = script
...
... [script]
... recipe = lovely.recipe:mkfile
... createpath = On
... path = subdir/for/file/file.sh
... content = hoschi
... mode = 0755
... """)
>>> print system(buildout)
Uninstalling script.
Installing script.
script: Creating directory /sample-buildout/subdir/for/file
script: Writing file /sample-buildout/subdir/for/file/file.sh
>>> ls(sample_buildout + '/subdir/for/file')
-  file.sh

File Variations

A common use-case is to have variations of a file, for example if init scripts have to be created. As an example we create two files with variations “1” and “2”. These variations can be used in the file path and in the content of the file via normal string formatting notation.

>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... parts = script
...
... [script]
... recipe = lovely.recipe:mkfile
... variations = 1 2
... path = prod_%(variation)s.ini
... content = hoschi variation %(variation)s
... mode = 0755
... """)
>>> print system(buildout)
Uninstalling script.
Installing script.
script: Writing file ...sample-buildout/prod_1.ini
script: Writing file ...sample-buildout/prod_2.ini
>>> cat(sample_buildout, 'prod_1.ini')
hoschi variation 1
>>> cat(sample_buildout, 'prod_2.ini')
hoschi variation 2

Egg Box Buildout Recipe

This recipe is derivd from zc.recipe.egg, but instead of just creating paths, it generates a directory structure for each top-level namespace. It is also possible to automatically zip the generated directories which is espacially usefull if used in Google Appengine environments. The recipies path option is filled with the created path so it can be referenced by other buildout sections which may want to use the recipe.

>>> import os
>>> lovely_recipy_loc = os.path.dirname(os.path.dirname(os.path.dirname(
...     os.path.dirname(os.path.dirname(__file__)))))
>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... develop = %(loc)s
... parts = packages
... find-links = %(server)s
... index = %(server)s/index
...
... [packages]
... recipe = lovely.recipe:eggbox
... eggs = demo
...        lovely.recipe
... interpreter = py
... """ % dict(loc=lovely_recipy_loc, server=link_server))
>>> print system(buildout)
Develop: '...lovely.recipe'
Getting distribution for 'demo'.
Got demo 0.4c1.
Getting distribution for 'demoneeded'.
Got demoneeded 1.2c1.
Installing packages.
Generated script '...sample-buildout/bin/demo'.
Generated interpreter '...sample-buildout/bin/py'.

We now have a zip file for each top-level directory. Note that the zip-files are ending with .egg for pkg_resources compatibility.

>>> ls(sample_buildout + '/parts/packages')
-  easy_install.py.egg
-  eggrecipedemo.py.egg
-  eggrecipedemoneeded.py.egg
-  lovely.egg
-  pkg_resources.py.egg
-  setuptools.egg
-  zc.egg

The generated interpreter now has the demo zip file in the path.

>>> cat(sample_buildout + '/bin/py')
#!...
sys.path[0:0] = [
  '/sample-buildout/parts/packages/easy_install.py.egg',
  '/sample-buildout/parts/packages/eggrecipedemo.py.egg',
  '/sample-buildout/parts/packages/eggrecipedemoneeded.py.egg',
  '/sample-buildout/parts/packages/lovely.egg',
  '/sample-buildout/parts/packages/pkg_resources.py.egg',
  '/sample-buildout/parts/packages/setuptools.egg',
  '/sample-buildout/parts/packages/zc.egg',
  ]...

It is possible to disable zipping. And also to exclude or include patterns of files. So for example we can strip down the uneeded setuptools egg. We can also create a script.

>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... develop = %(loc)s
... parts = packages test
... find-links = %(server)s
... index = %(server)s/index
...
... [packages]
... zip = False
... recipe = lovely.recipe:eggbox
... eggs = demo
...        lovely.recipe
... excludes = ^setuptools/.*
...            ^easy_install.*
...            ^pkg_resources.*
...
... [test]
... recipe = zc.recipe.egg:scripts
... eggs = lovely.recipe
... extra-paths = ${packages:path}
... interpreter = py
... """ % dict(loc=lovely_recipy_loc, server=link_server))
>>> print system(buildout),
Develop: '/Users/bd/sandbox/lovely.recipe'
Uninstalling packages.
Installing packages.
Generated script '/sample-buildout/bin/demo'.
Installing test.
Generated interpreter '/sample-buildout/bin/py'.

Note that we still have the same directory structure as the zipped version with a directory for each top-level namespace. The ‘lovely’ directory is not in he packages directory because it is a develop egg and we have set zipped to false, therefore it is only added to the python path.

>>> ls(sample_buildout + '/parts/packages')
d  eggrecipedemo.py
d  eggrecipedemoneeded.py
d  zc
>>> print system(join(sample_buildout, 'bin', 'py') + \
...        ' -c "import lovely.recipe; print lovely.recipe.__file__"')
/.../src/lovely/recipe/__init__.py...

The test section uses the path of our packages section. Note that due, to the development path of lovely.recipe this path is actually included twice because the script recipe does not check duplicates.

>>> cat(sample_buildout + '/bin/py')
#!...
sys.path[0:0] = [
  '/...lovely.recipe/src',
  ...
  '/.../lovely.recipe/src',
  '/sample-buildout/parts/packages/eggrecipedemo.py',
  '/sample-buildout/parts/packages/eggrecipedemoneeded.py',
  '/sample-buildout/parts/packages/zc',
  ]...

i18n Tools Recipe

This recipe allows to create i18n tools to extract and merge po files.

Creating The Tools

>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... parts = i18n
... index = http://download.zope.org/zope3.4
... offline = true
...
... [i18n]
... recipe = lovely.recipe:i18n
... package = lovely.recipe
... domain = recipe
... location = src/somewhere
... output = locales
... maker = z3c.csvvocabulary.csvStrings
... """)
>>> print system(buildout),
Installing i18n.
i18n: setting up i18n tools
Generated script 'bin/i18nextract'.
Generated script 'bin/i18nmergeall'.
Generated script 'bin/i18nstats'.
>>> import os
>>> ls(os.path.join(sample_buildout, 'bin'))
-  buildout
-  i18nextract
-  i18nmergeall
-  i18nstats

The i18n Extractor

>>> cat('bin', 'i18nextract')
#!...
<BLANKLINE>
import sys
sys.path[0:0] = [
...
  ]
<BLANKLINE>
import lovely.recipe.i18n.i18nextract
<BLANKLINE>
if __name__ == '__main__':
    lovely.recipe.i18n.i18nextract.main(['i18nextract', '-d', 'recipe', '-s', '/sample-buildout/parts/i18n/configure.zcml', '-p', 'src/somewhere', '-o', 'locales', '-m', 'z3c.csvvocabulary.csvStrings'])

We have a configure.zcml created.

>>> cat('parts', 'i18n', 'configure.zcml')
<configure xmlns='http://namespaces.zope.org/zope'>
  <include package="lovely.recipe" />
</configure>

i18n Merge

>>> cat('bin', 'i18nmergeall')
#!...
<BLANKLINE>
import sys
sys.path[0:0] = [
...
  ]
<BLANKLINE>
import lovely.recipe.i18n.i18nmergeall
<BLANKLINE>
if __name__ == '__main__':
    lovely.recipe.i18n.i18nmergeall.main(['i18nmergeall', '-l', 'src/somewhere/locales'])

i18n Stats

>>> cat('bin', 'i18nstats')
#!...
<BLANKLINE>
import sys
sys.path[0:0] = [
...
  ]
<BLANKLINE>
import lovely.recipe.i18n.i18nstats
<BLANKLINE>
if __name__ == '__main__':
    lovely.recipe.i18n.i18nstats.main(['i18nstats', '-l', 'src/somewhere/locales'])

Tool Names

The created tools are named after the section name. If the section for the recipe is named ‘translation’ then the tools are named ‘translationextract’ and ‘translationmergeall’.

>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... index = http://download.zope.org/zope3.4
... parts = translation
...
... offline = true
...
... [translation]
... recipe = lovely.recipe:i18n
... package = lovely.recipe
... domain = recipe
... location = src/somewhere
... output = locales
... maker = z3c.csvvocabulary.csvStrings
... """)
>>> print system(buildout),
Uninstalling i18n.
Installing translation.
translation: setting up i18n tools
Generated script 'bin/translationextract'.
Generated script 'bin/translationmergeall'.
Generated script 'bin/translationstats'.

Adding a custom configure.zcml

The created configure.zcml includes the package an assumes that the package contains a configure.zcml. If this is not the case or if additional package includes are needed then the zcml parameter can be used to define the content of the generated configure.zcml.

>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... parts = i18n
...
... offline = true
...
... [i18n]
... recipe = lovely.recipe:i18n
... package = lovely.recipe
... domain = recipe
... location = src/somewhere
... output = locales
... maker = z3c.csvvocabulary.csvStrings
... zcml =
...    <include package='zope.component' file='meta.zcml' />
...    <include package='lovely.recipe' />
...
... """)
>>> print system(buildout),
Uninstalling translation.
Installing i18n.
i18n: setting up i18n tools
Generated script 'bin/i18nextract'.
Generated script 'bin/i18nmergeall'.
Generated script 'bin/i18nstats'.
>>> cat('bin', 'i18nextract')
#!...
<BLANKLINE>
import sys
sys.path[0:0] = [
...
  ]
<BLANKLINE>
import lovely.recipe.i18n.i18nextract
<BLANKLINE>
if __name__ == '__main__':
    lovely.recipe.i18n.i18nextract.main(['i18nextract', '-d', 'recipe', '-s', '/sample-buildout/parts/i18n/configure.zcml', '-p', 'src/somewhere', '-o', 'locales', '-m', 'z3c.csvvocabulary.csvStrings'])

And the generated configure-zcml contains our extra code.

>>> cat('parts', 'i18n', 'configure.zcml')
<configure xmlns='http://namespaces.zope.org/zope'
           xmlns:meta="http://namespaces.zope.org/meta"
           >
<BLANKLINE>
<BLANKLINE>
<include package='zope.component' file='meta.zcml' />
<include package='lovely.recipe' />
<BLANKLINE>
</configure>

Importchecker Recipe

This recipe creates an importchecker instance in the bin directory.

Creating The Script

>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... parts = checker
...
... offline = true
...
... [checker]
... recipe = lovely.recipe:importchecker
... path = src/lovely
... """)
>>> print system(buildout),
Installing checker.
checker: setting up importchecker
Generated script 'bin/importchecker'.
>>> import os
>>> ls(os.path.join(sample_buildout, 'bin'))
-  buildout
-  importchecker
>>> cat('bin', 'importchecker')
#!...
<BLANKLINE>
import sys
sys.path[0:0] = [
  ...
  ]
<BLANKLINE>
import lovely.recipe.importchecker.importchecker
<BLANKLINE>
if __name__ == '__main__':
    lovely.recipe.importchecker.importchecker.main(['importchecker', 'src/lovely'])

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lovely.recipe-1.0.0.tar.gz (25.1 kB view hashes)

Uploaded Source

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page