diff --git a/CHANGES.rst b/CHANGES.rst index bbc92bdd9..fbc683fe1 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -10,6 +10,9 @@ Unreleased - Add ``BUILDOUT_HOME`` as an alternate way to control how the user default configuration is found. +- Fix edgecase where using multiple inheritance and increments can result in + some increments not being included in the final value + 2.2.1 (2013-09-05) ================== diff --git a/src/zc/buildout/buildout.py b/src/zc/buildout/buildout.py index 741c47cfe..7f592b1af 100644 --- a/src/zc/buildout/buildout.py +++ b/src/zc/buildout/buildout.py @@ -227,6 +227,16 @@ def __init__(self, config_file, cloptions, # apply command-line options _update(data, cloptions) + # convert any remaining += to = + for sectionname in data: + section = data[sectionname] + s2 = section.copy() + for k, v in s2.items(): + if k.endswith('+'): + key = k.rstrip(' +') + section[key] = v + del section[k] + # Set up versions section, if necessary if 'versions' not in data['buildout']: data['buildout']['versions'] = ('versions', 'DEFAULT_VALUE') @@ -1651,11 +1661,20 @@ def _update_section(s1, s2): if k.endswith('+'): key = k.rstrip(' +') # Find v1 in s2 first; it may have been defined locally too. - v1, note1 = s2.get(key, s1.get(key, ("", ""))) + v1, note1 = s2.get(key, s1.get(key, s1.get(k, ("", "")))) + if v1 == '': + # merging += in nothing. Keep as += + key = key + " +" + elif k in s1: + # merging += into +=. keep as += + key = key + " +" + del s1[k] + else: + # merging += into =. convert to = + del s2[k] newnote = ' [+] '.join((note1, note2)).strip() s2[key] = "\n".join((v1).split('\n') + v2.split('\n')), newnote - del s2[k] elif k.endswith('-'): key = k.rstrip(' -') # Find v1 in s2 first; it may have been set by a += operation first diff --git a/src/zc/buildout/tests.py b/src/zc/buildout/tests.py index 21a1f5328..a93ee233e 100644 --- a/src/zc/buildout/tests.py +++ b/src/zc/buildout/tests.py @@ -2671,6 +2671,45 @@ def increment_buildout_with_multiple_extended_files_421022(): recipe='zc.buildout:debug' """ +def increment_buildout_with_multiple_extended_without_base_equals(): + r""" + + >>> write('buildout.cfg', ''' + ... [buildout] + ... extends = base1.cfg base2.cfg + ... parts += foo + ... [foo] + ... recipe = zc.buildout:debug + ... [base1] + ... recipe = zc.buildout:debug + ... [base2] + ... recipe = zc.buildout:debug + ... ''') + >>> write('base1.cfg', ''' + ... [buildout] + ... extends = base3.cfg + ... parts += base1 + ... ''') + >>> write('base2.cfg', ''' + ... [buildout] + ... extends = base3.cfg + ... parts += base2 + ... ''') + >>> write('base3.cfg', ''' + ... [buildout] + ... ''') + + >>> print_(system(buildout), end='') + Installing base1. + recipe='zc.buildout:debug' + Installing base2. + recipe='zc.buildout:debug' + Installing foo. + recipe='zc.buildout:debug' + """ + + + def increment_on_command_line(): r""" >>> write('buildout.cfg', '''