Perform str_replace trying to match longest string first
Purpose is to avoid str_replace from doing partial replace
when a shorter instance of a matching key is found.
Conflicts:
heat/engine/hot/functions.py
Change-Id: I63c13f4eb3b1375cb2df1a34fd4f09561564f400
Co-Authored-By: Zane Bitter <zbitter@redhat.com>
Closes-Bug: 1600209
(cherry picked from commit a2f5b5cb9a
)
This commit is contained in:
parent
1ed38cdbce
commit
f32dbe7838
|
@ -394,8 +394,9 @@ class Replace(function.Function):
|
|||
|
||||
"<value_1> <value_2>"
|
||||
|
||||
This is implemented using python str.replace on each key. The order in
|
||||
which replacements are performed is undefined.
|
||||
This is implemented using python str.replace on each key. Longer keys are
|
||||
substituted before shorter ones, but the order in which replacements are
|
||||
performed is otherwise undefined.
|
||||
"""
|
||||
|
||||
def __init__(self, stack, fn_name, args):
|
||||
|
@ -455,6 +456,9 @@ class Replace(function.Function):
|
|||
|
||||
return string.replace(placeholder, six.text_type(value))
|
||||
|
||||
mapping = collections.OrderedDict(sorted(mapping.items(),
|
||||
key=lambda t: len(t[0]),
|
||||
reverse=True))
|
||||
return six.moves.reduce(replace, six.iteritems(mapping), template)
|
||||
|
||||
|
||||
|
|
|
@ -247,8 +247,9 @@ class Replace(cfn_funcs.Replace):
|
|||
|
||||
"<value_1> <value_2>"
|
||||
|
||||
This is implemented using Python's str.replace on each key. The order in
|
||||
which replacements are performed is undefined.
|
||||
This is implemented using python str.replace on each key. Longer keys are
|
||||
substituted before shorter ones, but the order in which replacements are
|
||||
performed is otherwise undefined.
|
||||
"""
|
||||
|
||||
def _parse_args(self):
|
||||
|
@ -275,9 +276,25 @@ class ReplaceJson(Replace):
|
|||
'''
|
||||
A function for performing string substitutions.
|
||||
|
||||
Behaves the same as Replace, but tolerates non-string parameter
|
||||
values, e.g map/list - these are serialized as json before doing
|
||||
the string substitution.
|
||||
Takes the form::
|
||||
|
||||
str_replace:
|
||||
template: <key_1> <key_2>
|
||||
params:
|
||||
<key_1>: <value_1>
|
||||
<key_2>: <value_2>
|
||||
...
|
||||
|
||||
And resolves to::
|
||||
|
||||
"<value_1> <value_2>"
|
||||
|
||||
This is implemented using python str.replace on each key. Longer keys are
|
||||
substituted before shorter ones, but the order in which replacements are
|
||||
performed is otherwise undefined.
|
||||
|
||||
Non-string param values (e.g maps or lists) are serialized as JSON before
|
||||
being substituted in.
|
||||
'''
|
||||
|
||||
def result(self):
|
||||
|
@ -319,6 +336,9 @@ class ReplaceJson(Replace):
|
|||
|
||||
return string.replace(placeholder, six.text_type(value))
|
||||
|
||||
mapping = collections.OrderedDict(sorted(mapping.items(),
|
||||
key=lambda t: len(t[0]),
|
||||
reverse=True))
|
||||
return six.moves.reduce(replace, six.iteritems(mapping), template)
|
||||
|
||||
|
||||
|
|
|
@ -558,6 +558,26 @@ class HOTemplateTest(common.HeatTestCase):
|
|||
|
||||
self.assertEqual(snippet_resolved, self.resolve(snippet, tmpl))
|
||||
|
||||
def test_str_replace_order(self, tpl=hot_tpl_empty):
|
||||
"""Test str_replace function substitution order."""
|
||||
|
||||
snippet = {'str_replace': {'template': '1234567890',
|
||||
'params': {'1': 'a',
|
||||
'12': 'b',
|
||||
'123': 'c',
|
||||
'1234': 'd',
|
||||
'12345': 'e',
|
||||
'123456': 'f',
|
||||
'1234567': 'g'}}}
|
||||
|
||||
tmpl = template.Template(tpl)
|
||||
|
||||
self.assertEqual('g890', self.resolve(snippet, tmpl))
|
||||
|
||||
def test_str_replace_liberty_order(self):
|
||||
"""Test str_replace function substitution order."""
|
||||
self.test_str_replace_order(hot_liberty_tpl_empty)
|
||||
|
||||
def test_str_replace_syntax(self):
|
||||
"""
|
||||
Test str_replace function syntax.
|
||||
|
|
Loading…
Reference in New Issue