merge: write manifestmerge() using dictionary with entry per file
authorMartin von Zweigbergk <martinvonz@google.com>
Mon, 08 Dec 2014 13:24:10 -0800
changeset 23637 13f53a2aa342
parent 23636 ab3b8d8fd2a0
child 23638 09be050ca98c
merge: write manifestmerge() using dictionary with entry per file In the same vein as 38e55e55ae4d (largefiles: rewrite merge code using dictionary with entry per file, 2014-12-09), rewrite manifestmerge() itself as dictionary with the filename as key. This will let us simplify some of the other code in merge.py and eventually drop the conversion in the largefiles code. No difference in speed could be detected (well within the noise level when run in Mozilla repo).
mercurial/merge.py
--- a/mercurial/merge.py	Wed Dec 17 12:21:07 2014 -0800
+++ b/mercurial/merge.py	Mon Dec 08 13:24:10 2014 -0800
@@ -375,7 +375,6 @@
     acceptremote = accept the incoming changes without prompting
     """
 
-    actions = dict((m, []) for m in 'a f g cd dc r dm dg m e k'.split())
     copy, movewithdir, diverge, renamedelete = {}, {}, {}, {}
 
     # manifests fetched in order are going to be faster, so prime the caches
@@ -406,6 +405,7 @@
     # Compare manifests
     diff = m1.diff(m2)
 
+    actions = {}
     for f, ((n1, fl1), (n2, fl2)) in diff.iteritems():
         if partial and not partial(f):
             continue
@@ -413,77 +413,76 @@
             if f not in ma:
                 fa = copy.get(f, None)
                 if fa is not None:
-                    actions['m'].append((f, (f, f, fa, False, pa.node()),
-                                   "both renamed from " + fa))
+                    actions[f] = ('m', (f, f, fa, False, pa.node()),
+                                  "both renamed from " + fa)
                 else:
-                    actions['m'].append((f, (f, f, None, False, pa.node()),
-                                   "both created"))
+                    actions[f] = ('m', (f, f, None, False, pa.node()),
+                                  "both created")
             else:
                 a = ma[f]
                 fla = ma.flags(f)
                 nol = 'l' not in fl1 + fl2 + fla
                 if n2 == a and fl2 == fla:
-                    actions['k'].append((f, (), "remote unchanged"))
+                    actions[f] = ('k' , (), "remote unchanged")
                 elif n1 == a and fl1 == fla: # local unchanged - use remote
                     if n1 == n2: # optimization: keep local content
-                        actions['e'].append((f, (fl2,), "update permissions"))
+                        actions[f] = ('e', (fl2,), "update permissions")
                     else:
-                        actions['g'].append((f, (fl2,), "remote is newer"))
+                        actions[f] = ('g', (fl2,), "remote is newer")
                 elif nol and n2 == a: # remote only changed 'x'
-                    actions['e'].append((f, (fl2,), "update permissions"))
+                    actions[f] = ('e', (fl2,), "update permissions")
                 elif nol and n1 == a: # local only changed 'x'
-                    actions['g'].append((f, (fl1,), "remote is newer"))
+                    actions[f] = ('g', (fl1,), "remote is newer")
                 else: # both changed something
-                    actions['m'].append((f, (f, f, f, False, pa.node()),
-                                   "versions differ"))
+                    actions[f] = ('m', (f, f, f, False, pa.node()),
+                                   "versions differ")
         elif n1: # file exists only on local side
             if f in copied:
                 pass # we'll deal with it on m2 side
             elif f in movewithdir: # directory rename, move local
                 f2 = movewithdir[f]
                 if f2 in m2:
-                    actions['m'].append((f2, (f, f2, None, True, pa.node()),
-                                   "remote directory rename, both created"))
+                    actions[f2] = ('m', (f, f2, None, True, pa.node()),
+                                   "remote directory rename, both created")
                 else:
-                    actions['dm'].append((f2, (f, fl1),
-                                  "remote directory rename - move from " + f))
+                    actions[f2] = ('dm', (f, fl1),
+                                   "remote directory rename - move from " + f)
             elif f in copy:
                 f2 = copy[f]
-                actions['m'].append((f, (f, f2, f2, False, pa.node()),
-                                "local copied/moved from " + f2))
+                actions[f] = ('m', (f, f2, f2, False, pa.node()),
+                              "local copied/moved from " + f2)
             elif f in ma: # clean, a different, no remote
                 if n1 != ma[f]:
                     if acceptremote:
-                        actions['r'].append((f, None, "remote delete"))
+                        actions[f] = ('r', None, "remote delete")
                     else:
-                        actions['cd'].append((f, None,
-                                              "prompt changed/deleted"))
+                        actions[f] = ('cd', None,  "prompt changed/deleted")
                 elif n1[20:] == 'a':
                     # This extra 'a' is added by working copy manifest to mark
                     # the file as locally added. We should forget it instead of
                     # deleting it.
-                    actions['f'].append((f, None, "remote deleted"))
+                    actions[f] = ('f', None, "remote deleted")
                 else:
-                    actions['r'].append((f, None, "other deleted"))
+                    actions[f] = ('r', None, "other deleted")
         elif n2: # file exists only on remote side
             if f in copied:
                 pass # we'll deal with it on m1 side
             elif f in movewithdir:
                 f2 = movewithdir[f]
                 if f2 in m1:
-                    actions['m'].append((f2, (f2, f, None, False, pa.node()),
-                                   "local directory rename, both created"))
+                    actions[f2] = ('m', (f2, f, None, False, pa.node()),
+                                   "local directory rename, both created")
                 else:
-                    actions['dg'].append((f2, (f, fl2),
-                                    "local directory rename - get from " + f))
+                    actions[f2] = ('dg', (f, fl2),
+                                   "local directory rename - get from " + f)
             elif f in copy:
                 f2 = copy[f]
                 if f2 in m2:
-                    actions['m'].append((f, (f2, f, f2, False, pa.node()),
-                                    "remote copied from " + f2))
+                    actions[f] = ('m', (f2, f, f2, False, pa.node()),
+                                  "remote copied from " + f2)
                 else:
-                    actions['m'].append((f, (f2, f, f2, True, pa.node()),
-                                    "remote moved from " + f2))
+                    actions[f] = ('m', (f2, f, f2, True, pa.node()),
+                                  "remote moved from " + f2)
             elif f not in ma:
                 # local unknown, remote created: the logic is described by the
                 # following table:
@@ -498,26 +497,25 @@
                 # Checking whether the files are different is expensive, so we
                 # don't do that when we can avoid it.
                 if force and not branchmerge:
-                    actions['g'].append((f, (fl2,), "remote created"))
+                    actions[f] = ('g', (fl2,), "remote created")
                 else:
                     different = _checkunknownfile(repo, wctx, p2, f)
                     if force and branchmerge and different:
-                        actions['m'].append((f, (f, f, None, False, pa.node()),
-                                        "remote differs from untracked local"))
+                        actions[f] = ('m', (f, f, None, False, pa.node()),
+                                      "remote differs from untracked local")
                     elif not force and different:
                         aborts.append((f, 'ud'))
                     else:
-                        actions['g'].append((f, (fl2,), "remote created"))
+                        actions[f] = ('g', (fl2,), "remote created")
             elif n2 != ma[f]:
                 different = _checkunknownfile(repo, wctx, p2, f)
                 if not force and different:
                     aborts.append((f, 'ud'))
                 else:
                     if acceptremote:
-                        actions['g'].append((f, (fl2,), "remote recreating"))
+                        actions[f] = ('g', (fl2,), "remote recreating")
                     else:
-                        actions['dc'].append((f, (fl2,),
-                                              "prompt deleted/changed"))
+                        actions[f] = ('dc', (fl2,), "prompt deleted/changed")
 
     for f, m in sorted(aborts):
         if m == 'ud':
@@ -527,6 +525,12 @@
         raise util.Abort(_("untracked files in working directory differ "
                            "from files in requested revision"))
 
+    # Convert to dictionary-of-lists format
+    actionbyfile = actions
+    actions = dict((m, []) for m in 'a f g cd dc r dm dg m e k'.split())
+    for f, (m, args, msg) in actionbyfile.iteritems():
+        actions[m].append((f, args, msg))
+
     return actions, diverge, renamedelete
 
 def _resolvetrivial(repo, wctx, mctx, ancestor, actions):