Commit d42b790b authored by Jérome Perrin's avatar Jérome Perrin Committed by Julien Muchembled

Escape option values set by recipes

When recipe mutate options, options values are written to .installed.cfg
without escaping buildout substitution syntax, so if a recipe sets an option
value that could be interpreted as a buildout substitution, it is written as is
in .installed.cfg.
This can be a problem if options read from _read_installed_part_options are
accessed, like it's the case with slapos patched buildout which saves
installed options after an error with part installation or after each part
installation when running in verbose mode.
parent 32facc78
...@@ -1606,7 +1606,7 @@ class Options(DictMixin): ...@@ -1606,7 +1606,7 @@ class Options(DictMixin):
def __setitem__(self, option, value): def __setitem__(self, option, value):
if not isinstance(value, str): if not isinstance(value, str):
value = dumps(value) value = dumps(value)
self._data[option] = value self._data[option] = value.replace('${', '$${')
def __delitem__(self, key): def __delitem__(self, key):
if key in self._raw: if key in self._raw:
......
...@@ -2166,6 +2166,60 @@ def test_part_pulled_by_recipe(): ...@@ -2166,6 +2166,60 @@ def test_part_pulled_by_recipe():
... ...
""" """
def test_recipe_options_are_escaped():
"""
>>> mkdir(sample_buildout, 'recipes')
>>> write(sample_buildout, 'recipes', 'test.py',
... '''
... class Recipe:
...
... def __init__(self, buildout, name, options):
... options['option'] = '${buildout_syntax_should_be_escaped}'
... print ("Option value: %s" % options['option'])
...
... def install(self):
... return ()
...
... update = install
... ''')
>>> write(sample_buildout, 'recipes', 'setup.py',
... '''
... from setuptools import setup
... setup(
... name = "recipes",
... entry_points = {'zc.buildout': ['test = test:Recipe']},
... )
... ''')
>>> write(sample_buildout, 'buildout.cfg',
... '''
... [buildout]
... develop = recipes
... parts = a
... [a]
... recipe = recipes:test
... ''')
>>> os.chdir(sample_buildout)
>>> buildout = os.path.join(sample_buildout, 'bin', 'buildout')
>>> print_(system(buildout), end='')
Develop: '/sample-buildout/recipes'
Option value: ${buildout_syntax_should_be_escaped}
Installing a.
>>> cat('.installed.cfg') # doctest: +ELLIPSIS
[buildout]
...
[a]
__buildout_installed__ =
__buildout_signature__ = recipes-...
option = $${buildout_syntax_should_be_escaped}
recipe = recipes:test
"""
def read_find_links_to_load_extensions(): def read_find_links_to_load_extensions():
r""" r"""
We'll create a wacky buildout extension that just announces itself when used: We'll create a wacky buildout extension that just announces itself when used:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment