浏览代码

Fix parsing of comments.

Jelmer Vernooij 13 年之前
父节点
当前提交
cb42ef5189
共有 2 个文件被更改,包括 46 次插入10 次删除
  1. 32 8
      dulwich/config.py
  2. 14 2
      dulwich/tests/test_config.py

+ 32 - 8
dulwich/config.py

@@ -112,11 +112,26 @@ def _format_string(value):
 
 def _parse_string(value):
     value = value.strip()
-    if value.startswith("\""):
-        if not value.endswith("\""):
-            raise ValueError("value starts with quote but lacks end quote")
-        return _unescape_value(value[1:-1])
-    return _unescape_value(value)
+    ret = []
+    block = []
+    in_quotes  = False
+    for c in value:
+        if c == "\"":
+            in_quotes = (not in_quotes)
+            ret.append(_unescape_value("".join(block)))
+            block = []
+        elif c in ("#", ";") and not in_quotes:
+            # the rest of the line is a comment
+            break
+        else:
+            block.append(c)
+
+    if in_quotes:
+        raise ValueError("value starts with quote but lacks end quote")
+
+    ret.append(_unescape_value("".join(block)).rstrip())
+
+    return "".join(ret)
 
 
 def _unescape_value(value):
@@ -151,6 +166,12 @@ def _check_section_name(name):
     return True
 
 
+def _strip_comments(line):
+    line = line.split("#")[0]
+    line = line.split(";")[0]
+    return line
+
+
 class ConfigFile(ConfigDict):
     """A Git configuration file, like .git/config or ~/.gitconfig.
     """
@@ -164,9 +185,12 @@ class ConfigFile(ConfigDict):
         for lineno, line in enumerate(f.readlines()):
             line = line.lstrip()
             if setting is None:
-                if line.strip() == "":
+                if _strip_comments(line).strip() == "":
                     continue
-                if line[0] == "[" and line.rstrip()[-1] == "]":
+                if line[0] == "[":
+                    line = _strip_comments(line).rstrip()
+                    if line[-1] != "]":
+                        raise ValueError("expected trailing ]")
                     key = line.strip()
                     pts = key[1:-1].split(" ", 1)
                     if len(pts) == 2:
@@ -209,7 +233,7 @@ class ConfigFile(ConfigDict):
                     ret._values[section][setting] = value
                     if not continuation:
                         setting = None
-            else:
+            else: # continuation line
                 if line.endswith("\\\n"):
                     line = line[:-2]
                     continuation = True

+ 14 - 2
dulwich/tests/test_config.py

@@ -54,17 +54,29 @@ class ConfigFileTests(TestCase):
 
     def test_comment_before_section(self):
         cf = self.from_file("# foo\n[section]\n")
-        self.assertEquals(ConfigFile(), cf)
+        self.assertEquals(ConfigFile({("section", ): {}}), cf)
 
     def test_comment_after_section(self):
         cf = self.from_file("[section] # foo\n")
-        self.assertEquals(ConfigFile(), cf)
+        self.assertEquals(ConfigFile({("section", ): {}}), cf)
+
+    def test_comment_after_variable(self):
+        cf = self.from_file("[section]\nbar= foo # a comment\n")
+        self.assertEquals(ConfigFile({("section", ): {"bar": "foo"}}), cf)
 
     def test_from_file_section(self):
         cf = self.from_file("[core]\nfoo = bar\n")
         self.assertEquals("bar", cf.get(("core", ), "foo"))
         self.assertEquals("bar", cf.get(("core", "foo"), "foo"))
 
+    def test_from_file_with_mixed_quoted(self):
+        cf = self.from_file("[core]\nfoo = \"bar\"la\n")
+        self.assertEquals("barla", cf.get(("core", ), "foo"))
+
+    def test_from_file_with_open_quoted(self):
+        self.assertRaises(ValueError,
+            self.from_file, "[core]\nfoo = \"bar\n")
+
     def test_from_file_with_quotes(self):
         cf = self.from_file(
             "[core]\n"