changeset 6892:f9b5deab451e

ini: add support for adding extra entries to sections When adding entries to an existing section, assume that comments and empty lines *before* a section header belongs to that section. That is an approximation; not always entirely correct, but the best we can come up with.
author Mads Kiilerich <mads@kiilerich.com>
date Thu, 14 Sep 2017 02:08:06 +0200
parents 7292c5976752
children d06039dc4ca2
files kallithea/lib/inifile.py
diffstat 1 files changed, 29 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/kallithea/lib/inifile.py	Thu Sep 14 02:08:06 2017 +0200
+++ b/kallithea/lib/inifile.py	Thu Sep 14 02:08:06 2017 +0200
@@ -67,13 +67,24 @@
     #variable2  =    value after tab
     variable2 = VAL2
     <BLANKLINE>
+    first_extra = EXTRA
+    <BLANKLINE>
     <BLANKLINE>
     # FUNCTION RESULT
     [second-section]
     # Description                                                                  #
     # of this config file                                                          #
     <BLANKLINE>
+    [fourth-section]
+    fourth = "four"
+    fourth_extra = 4
+    <BLANKLINE>
+    [third-section]
+    third_extra =  3
+    <BLANKLINE>
     """
+    settings = dict((k, dict(v)) for k, v in settings.items()) # deep copy before mutating
+
     ini_lines = mako.template.Template(template).render(**mako_variable_values)
 
     ini_lines = re.sub(
@@ -85,7 +96,7 @@
         """process a ini section, replacing values as necessary"""
         sectionname, lines = m.groups()
         if sectionname in settings:
-            section_settings = settings[sectionname]
+            section_settings = settings.pop(sectionname)
 
             def process_line(m):
                 """process a section line and update value if necessary"""
@@ -93,25 +104,37 @@
                 line = m.group(0)
                 if key in section_settings:
                     # keep old entry as example - comments might refer to it
-                    line = '#%s\n%s = %s' % (line, key, section_settings[key])
+                    line = '#%s\n%s = %s' % (line, key, section_settings.pop(key))
                 return line.rstrip()
 
             # process lines that not are comments or empty and look like name=value
             lines = re.sub(r'^([^#\n\s]*)[ \t]*=[ \t]*(.*)$', process_line, lines, flags=re.MULTILINE)
+            # add unused section settings
+            if section_settings:
+                lines += '\n' + ''.join('%s = %s\n' % (key, value) for key, value in sorted(section_settings.items()))
 
         return sectionname + '\n' + lines
 
-    # process sections until next section start or end
+    # process sections until comments before next section or end
     ini_lines = re.sub(r'''^
         (\[.*\])\n
         # after the section name, a number of chunks with:
         (
             (?:
-                # a number of empty or non-section-start lines
-                (?:[^\n[].*)?\n
+                # a number of comments or empty lines
+                (?:[#].*\n|\n)*
+                # one or more non-empty non-comments non-section-start lines
+                (?:[^\n#[].*\n)+
+                # a number of comments - not empty lines
+                (?:[#].*\n)*
             )*
         )
         ''',
-        process_section, ini_lines, flags=re.MULTILINE|re.VERBOSE)
+        process_section, ini_lines, flags=re.MULTILINE|re.VERBOSE) \
+        + \
+        ''.join(
+            '\n' + sectionname + '\n' + ''.join('%s = %s\n' % (key, value) for key, value in sorted(section_settings.items()))
+            for sectionname, section_settings in sorted(settings.items())
+            if section_settings)
 
     return ini_lines