summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--git/config.py30
-rw-r--r--git/test/fixtures/git_config_values4
-rw-r--r--git/test/test_config.py26
3 files changed, 56 insertions, 4 deletions
diff --git a/git/config.py b/git/config.py
index c71bb8ca..620f7b10 100644
--- a/git/config.py
+++ b/git/config.py
@@ -245,8 +245,28 @@ class GitConfigParser(cp.RawConfigParser, object):
if pos != -1 and optval[pos-1].isspace():
optval = optval[:pos]
optval = optval.strip()
- if optval == '""':
- optval = ''
+
+ # Remove paired unescaped-quotes
+ unquoted_optval = ''
+ escaped = False
+ in_quote = False
+ for c in optval:
+ if not escaped and c == '"':
+ in_quote = not in_quote
+ else:
+ escaped = (c == '\\') and not escaped
+ unquoted_optval += c
+
+ if in_quote:
+ if not e:
+ e = cp.ParsingError(fpname)
+ e.append(lineno, repr(line))
+
+ optval = unquoted_optval
+
+ optval = optval.replace('\\\\', '\\') # Unescape backslashes
+ optval = optval.replace(r'\"', '"') # Unescape quotes
+
optname = self.optionxform(optname.rstrip())
cursect[optname] = optval
else:
@@ -303,7 +323,11 @@ class GitConfigParser(cp.RawConfigParser, object):
fp.write("[%s]\n" % name)
for (key, value) in section_dict.items():
if key != "__name__":
- fp.write("\t%s = %s\n" % (key, str(value).replace('\n', '\n\t')))
+ value = str(value)
+ value = value.replace('\\', '\\\\') # Escape backslashes
+ value = value.replace('"', r'\"') # Escape quotes
+ value = value.replace('\n', '\n\t')
+ fp.write("\t%s = %s\n" % (key, value))
# END if key is not __name__
# END section writing
diff --git a/git/test/fixtures/git_config_values b/git/test/fixtures/git_config_values
new file mode 100644
index 00000000..5ba039ef
--- /dev/null
+++ b/git/test/fixtures/git_config_values
@@ -0,0 +1,4 @@
+[values]
+ backslash = some\\data
+ quote = this is a \"quoted value\"
+ quoted = "all" "your \"quotes\" a"re bel"ong to """"us"
diff --git a/git/test/test_config.py b/git/test/test_config.py
index d2e199e3..b37db290 100644
--- a/git/test/test_config.py
+++ b/git/test/test_config.py
@@ -101,4 +101,28 @@ class TestConfig(TestBase):
# it raises if there is no default though
self.failUnlessRaises(NoSectionError, r_config.get_value, "doesnt", "exist")
-
+ def test_values(self):
+ file_obj = self._to_memcache(fixture_path("git_config_values"))
+ w_config = GitConfigParser(file_obj, read_only = False)
+ w_config.write() # enforce writing
+ orig_value = file_obj.getvalue()
+
+ # Reading must unescape backslashes
+ backslash = w_config.get('values', 'backslash')
+ assert backslash == r'some\data'
+
+ # Reading must unescape quotes
+ quote = w_config.get('values', 'quote')
+ assert quote == 'this is a "quoted value"'
+
+ # Reading must remove surrounding quotes
+ quoted = w_config.get('values', 'quoted')
+ assert quoted == 'all your "quotes" are belong to us'
+
+ # Writing must escape backslashes and quotes
+ w_config.set('values', 'backslash', backslash)
+ w_config.set('values', 'quote', quote)
+ w_config.write() # enforce writing
+
+ # Contents shouldn't differ
+ assert file_obj.getvalue() == orig_value