]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
ceph-volume configuration allow inlined comments for # and ;
authorAlfredo Deza <adeza@redhat.com>
Mon, 4 Dec 2017 13:22:23 +0000 (08:22 -0500)
committerAlfredo Deza <adeza@redhat.com>
Thu, 7 Dec 2017 19:45:39 +0000 (14:45 -0500)
Signed-off-by: Alfredo Deza <adeza@redhat.com>
src/ceph-volume/ceph_volume/configuration.py

index e4f9bde2fed0e029e0ff51470e0ec235d19dced0..f515b8c9eae94cf2aab1ae72f6547f0b93cb1def 100644 (file)
@@ -36,6 +36,7 @@ def load(abspath=None):
         raise exceptions.ConfigurationError(abspath=abspath)
 
     parser = Conf()
+
     try:
         ceph_file = open(abspath)
         trimmed_conf = _TrimIndentFile(ceph_file)
@@ -101,3 +102,101 @@ class Conf(configparser.SafeConfigParser):
 
         # strip spaces
         return [x.strip() for x in value]
+
+    # XXX Almost all of it lifted from the original ConfigParser._read method,
+    # except for the parsing of '#' in lines. This is only a problem in Python 2.7, and can be removed
+    # once tooling is Python3 only with `Conf(inline_comment_prefixes=('#',';'))`
+    def _read(self, fp, fpname):
+        """Parse a sectioned setup file.
+
+        The sections in setup file contains a title line at the top,
+        indicated by a name in square brackets (`[]'), plus key/value
+        options lines, indicated by `name: value' format lines.
+        Continuations are represented by an embedded newline then
+        leading whitespace.  Blank lines, lines beginning with a '#',
+        and just about everything else are ignored.
+        """
+        cursect = None                        # None, or a dictionary
+        optname = None
+        lineno = 0
+        e = None                              # None, or an exception
+        while True:
+            line = fp.readline()
+            if not line:
+                break
+            lineno = lineno + 1
+            # comment or blank line?
+            if line.strip() == '' or line[0] in '#;':
+                continue
+            if line.split(None, 1)[0].lower() == 'rem' and line[0] in "rR":
+                # no leading whitespace
+                continue
+            # continuation line?
+            if line[0].isspace() and cursect is not None and optname:
+                value = line.strip()
+                if value:
+                    cursect[optname].append(value)
+            # a section header or option header?
+            else:
+                # is it a section header?
+                mo = self.SECTCRE.match(line)
+                if mo:
+                    sectname = mo.group('header')
+                    if sectname in self._sections:
+                        cursect = self._sections[sectname]
+                    elif sectname == 'DEFAULT':
+                        cursect = self._defaults
+                    else:
+                        cursect = self._dict()
+                        cursect['__name__'] = sectname
+                        self._sections[sectname] = cursect
+                    # So sections can't start with a continuation line
+                    optname = None
+                # no section header in the file?
+                elif cursect is None:
+                    raise configparser.MissingSectionHeaderError(fpname, lineno, line)
+                # an option line?
+                else:
+                    mo = self._optcre.match(line)
+                    if mo:
+                        optname, vi, optval = mo.group('option', 'vi', 'value')
+                        optname = self.optionxform(optname.rstrip())
+                        # This check is fine because the OPTCRE cannot
+                        # match if it would set optval to None
+                        if optval is not None:
+                            # XXX Added support for '#' inline comments
+                            if vi in ('=', ':') and (';' in optval or '#' in optval):
+                                # strip comments
+                                optval = re.split(r'\s+(;|#)', optval)[0]
+                                # if what is left is comment as a value, fallback to an empty string
+                                # that is: `foo = ;` would mean `foo` is '', which brings parity with
+                                # what ceph-conf tool does
+                                if optval in [';','#']:
+                                    optval = ''
+                            optval = optval.strip()
+                            # allow empty values
+                            if optval == '""':
+                                optval = ''
+                            cursect[optname] = [optval]
+                        else:
+                            # valueless option handling
+                            cursect[optname] = optval
+                    else:
+                        # a non-fatal parsing error occurred.  set up the
+                        # exception but keep going. the exception will be
+                        # raised at the end of the file and will contain a
+                        # list of all bogus lines
+                        if not e:
+                            e = configparser.ParsingError(fpname)
+                        e.append(lineno, repr(line))
+        # if any parsing errors occurred, raise an exception
+        if e:
+            raise e
+
+        # join the multi-line values collected while reading
+        all_sections = [self._defaults]
+        all_sections.extend(self._sections.values())
+        for options in all_sections:
+            for name, val in options.items():
+                if isinstance(val, list):
+                    options[name] = '\n'.join(val)