diff options
Diffstat (limited to 'git/config.py')
-rw-r--r-- | git/config.py | 105 |
1 files changed, 67 insertions, 38 deletions
diff --git a/git/config.py b/git/config.py index eefab299..5828a1c1 100644 --- a/git/config.py +++ b/git/config.py @@ -22,7 +22,8 @@ from git.compat import ( string_types, FileType, defenc, - with_metaclass + with_metaclass, + PY3 ) __all__ = ('GitConfigParser', 'SectionConstraint') @@ -243,7 +244,21 @@ class GitConfigParser(with_metaclass(MetaParserBuilder, cp.RawConfigParser, obje cursect = None # None, or a dictionary optname = None lineno = 0 + is_multi_line = False e = None # None, or an exception + + def string_decode(v): + if v[-1] == '\\': + v = v[:-1] + # end cut trailing escapes to prevent decode error + + if PY3: + return v.encode(defenc).decode('unicode_escape') + else: + return v.decode('string_escape') + # end + # end + while True: # we assume to read binary ! line = fp.readline().decode(defenc) @@ -256,46 +271,60 @@ class GitConfigParser(with_metaclass(MetaParserBuilder, cp.RawConfigParser, obje if line.split(None, 1)[0].lower() == 'rem' and line[0] in "rR": # no leading whitespace continue - else: - # is it a section header? - mo = self.SECTCRE.match(line.strip()) + + # is it a section header? + mo = self.SECTCRE.match(line.strip()) + if not is_multi_line and mo: + sectname = mo.group('header').strip() + if sectname in self._sections: + cursect = self._sections[sectname] + elif sectname == cp.DEFAULTSECT: + cursect = self._defaults + else: + cursect = self._dict((('__name__', sectname),)) + self._sections[sectname] = cursect + self._proxies[sectname] = None + # So sections can't start with a continuation line + optname = None + # no section header in the file? + elif cursect is None: + raise cp.MissingSectionHeaderError(fpname, lineno, line) + # an option line? + elif not is_multi_line: + mo = self.OPTCRE.match(line) if mo: - sectname = mo.group('header').strip() - if sectname in self._sections: - cursect = self._sections[sectname] - elif sectname == cp.DEFAULTSECT: - cursect = self._defaults - else: - cursect = self._dict((('__name__', sectname),)) - self._sections[sectname] = cursect - self._proxies[sectname] = None - # So sections can't start with a continuation line - optname = None - # no section header in the file? - elif cursect is None: - raise cp.MissingSectionHeaderError(fpname, lineno, line) - # an option line? + # We might just have handled the last line, which could contain a quotation we want to remove + optname, vi, optval = mo.group('option', 'vi', 'value') + if vi in ('=', ':') and ';' in optval: + pos = optval.find(';') + if pos != -1 and optval[pos - 1].isspace(): + optval = optval[:pos] + optval = optval.strip() + if optval == '""': + optval = '' + # end handle empty string + optname = self.optionxform(optname.rstrip()) + if len(optval) > 1 and optval[0] == '"' and optval[-1] != '"': + is_multi_line = True + optval = string_decode(optval[1:]) + # end handle multi-line + cursect[optname] = optval else: - mo = self.OPTCRE.match(line) - if mo: - optname, vi, optval = mo.group('option', 'vi', 'value') - if vi in ('=', ':') and ';' in optval: - pos = optval.find(';') - if pos != -1 and optval[pos - 1].isspace(): - optval = optval[:pos] - optval = optval.strip() - if optval == '""': - optval = '' - optname = self.optionxform(optname.rstrip()) - cursect[optname] = optval - else: - if not e: - e = cp.ParsingError(fpname) - e.append(lineno, repr(line)) - # END - # END ? - # END ? + if not e: + e = cp.ParsingError(fpname) + e.append(lineno, repr(line)) + print(lineno, line) + continue + else: + line = line.rstrip() + if line.endswith('"'): + is_multi_line = False + line = line[:-1] + # end handle quotations + cursect[optname] += string_decode(line) + # END parse section or option # END while reading + # if any parsing errors occurred, raise an exception if e: raise e |