From e1b77cf71448cda7a4c863646aa1798fda9aff75 Mon Sep 17 00:00:00 2001 From: Alfredo Deza Date: Mon, 4 Dec 2017 08:22:23 -0500 Subject: [PATCH] ceph-volume configuration allow inlined comments for # and ; Signed-off-by: Alfredo Deza --- src/ceph-volume/ceph_volume/configuration.py | 99 ++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/src/ceph-volume/ceph_volume/configuration.py b/src/ceph-volume/ceph_volume/configuration.py index e4f9bde2fed0e..f515b8c9eae94 100644 --- a/src/ceph-volume/ceph_volume/configuration.py +++ b/src/ceph-volume/ceph_volume/configuration.py @@ -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) -- 2.39.5