]> scripts.mit.edu Git - wizard.git/blobdiff - wizard/resolve.py
Remove string exception from remaster.
[wizard.git] / wizard / resolve.py
index 9259c245330c5d90140527f867d2ab65fa37cc17..4460cc6d8ce57ccb9efa44035b33677b6f6c876e 100644 (file)
@@ -12,10 +12,10 @@ for resolving conflicts in configuration files.
 The conflict resolution DSL is described here:
 
 Resolutions are specified as input-output pairs.  An input
-is a string with the conflict resolution markers ("<" * 7,
-"=" * 7 and ">" * 7), with the HEAD content above the equals
+is a string with the conflict resolution markers ``("<" * 7,
+"=" * 7 and ">" * 7)``, with the HEAD content above the equals
 divider, and the upstream content below the equals divider.
-Lines can also be marked as "***N***" where N is a natural
+Lines can also be marked as ``***N***`` where N is a natural
 number greater than 0 (i.e. 1 or more), which means that
 an arbitrary number of lines may be matched and available for output.
 
@@ -33,6 +33,8 @@ Here are some examples::
 
     <<<<<<<
     downstream
+    |||||||
+    common
     =======
     upstream
     >>>>>>>
@@ -83,12 +85,22 @@ def spec_to_regex(spec):
             else:
                 ret += re.escape(line)
         return ("(" + ret + ")", mappings)
-    ours_regex, ours_mappings = regexify(ours, -1, 1)
-    theirs_regex, theirs_mappings = regexify(theirs, 0, len(ours_mappings) + 1)
+    ours, split, common = ours.partition("|||||||\n")
+    if not split:
+        common = "***9999***\n" # force wildcard behavior
+    ours_regex, ours_mappings     = regexify(ours,   -1, 1)
+    common_regex, common_mappings = regexify(common, -2, 1 + len(ours_mappings))
+    theirs_regex, theirs_mappings = regexify(theirs,  0, 1 + len(ours_mappings) + len(common_mappings))
+    # unify the mappings
     ours_mappings.update(theirs_mappings)
-    return ("<<<<<<<[^\n]*\\\n" + ours_regex + "=======\\\n" + theirs_regex + ">>>>>>>[^\n]*(\\\n|$)", ours_mappings)
+    ours_mappings.update(common_mappings)
+    return ("<<<<<<<[^\n]*\\\n" + ours_regex + "\|\|\|\|\|\|\|\\\n" + common_regex + "=======\\\n" + theirs_regex + ">>>>>>>[^\n]*(\\\n|$)", ours_mappings)
 
 def result_to_repl(result, mappings):
+    """
+    Converts a list of replacement strings and or references
+    into a replacement string appropriate for a regular expression.
+    """
     def ritem_to_string(r):
         if type(r) is int:
             return "\\%d" % mappings[r]
@@ -97,6 +109,10 @@ def result_to_repl(result, mappings):
     return "".join(map(ritem_to_string, result))
 
 def resolve(contents, spec, result):
+    """
+    Given a conflicted file, whose contents are ``contents``, attempt
+    to resolve all conflicts that match ``spec`` with ``result``.
+    """
     rstring, mappings = spec_to_regex(spec)
     regex = re.compile(rstring, re.DOTALL)
     repl = result_to_repl(result, mappings)
@@ -106,10 +122,12 @@ def resolve(contents, spec, result):
     for line in contents.splitlines(True):
         if status == 0 and line.startswith("<<<<<<<"):
             status = 1
-        elif status == 1 and line.startswith("======="):
+        elif status == 1 and line.startswith("|||||||"):
             status = 2
+        elif status == 1 or status == 2 and line.startswith("======="):
+            status = 3
         # ok, now process
-        if status == 2 and line.startswith(">>>>>>>"):
+        if status == 3 and line.startswith(">>>>>>>"):
             status = 0
             conflict += line
             ret += regex.sub(repl, conflict)
@@ -121,23 +139,9 @@ def resolve(contents, spec, result):
     return ret
 
 def is_conflict(contents):
+    """
+    Given ``contents``, return ``True`` if there are any conflicts in it.
+    """
     # Really really simple heuristic
     return "<<<<<<<" in contents
 
-def fix_newlines(file, log=True):
-    """
-    Normalizes newlines in a file into UNIX file endings.  If
-    ``log`` is ``True`` an info log mesage is printed if
-    any normalization occurs.  Return value is ``True`` if
-    normalization occurred.
-    """
-    old_contents = open(file, "r").read()
-    contents = old_contents
-    while "\r\n" in contents:
-        contents = contents.replace("\r\n", "\n")
-    contents = contents.replace("\r", "\n")
-    if contents != old_contents:
-        logging.info("Converted %s to UNIX file endings" % file)
-        open(file, "w").write(contents)
-        return True
-    return False