[PATCH 1 of 3] cmdutil: add a function to terse the status

Pulkit Goyal 7895pulkit at gmail.com
Wed Jun 14 21:02:38 UTC 2017


# HG changeset patch
# User Pulkit Goyal <7895pulkit at gmail.com>
# Date 1497462524 -19800
#      Wed Jun 14 23:18:44 2017 +0530
# Node ID 622220c3eb0a6ae2f0e7dfc94ac103ad4bfc53aa
# Parent  f12a51d828c6bac3ed7683bd07f7d04232727da5
cmdutil: add a function to terse the status

This function will be used to terse the output of `hg status`. It collapses a
directory if all the files (except ignored) shares the same status and consider
ignored ones when ignore is passed through either terse or normally. A further
patch will add tests which will make things clearer.

diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -402,6 +402,115 @@
 
     return commit(ui, repo, recordinwlock, pats, opts)
 
+def tersestatus(repo, statlist, status, ignore):
+    """
+    Returns a list of statuses with directory collapsed if all the files in the
+    directory has the same status.
+    """
+
+    def numfiles(dirname):
+        """
+        Calculates the number of tracked files in a given directory which also
+        includes files which were removed or deleted. Considers ignored files
+        if ignore argument is True or 'i' is present in status argument.
+        """
+        if 'i' in status or ignore:
+            def match(fname):
+                return False
+        else:
+            match = repo.dirstate._ignore
+        lendir = 0
+        abspath = repo.root + pycompat.ossep + dirname
+        for f in os.listdir(abspath):
+            if not match(f):
+                lendir += 1
+        if absentdir.get(dirname):
+            lendir += absentdir[dirname]
+        return lendir
+
+    def absentones(removedfiles, missingfiles):
+        """
+        Returns a dictionary of directories and number of files which are either
+        removed or missing (deleted) in them.
+        """
+        absentdir = {}
+        absentfiles = removedfiles + missingfiles
+        while absentfiles:
+            f = absentfiles.pop()
+            par = os.path.dirname(f)
+            if par == '':
+                continue
+            try:
+                absentdir[par] += 1
+            except KeyError:
+                absentdir[par] = 1
+            if par not in removedfiles:
+                absentfiles.append(par)
+        return absentdir
+
+    indexes = {'m': 0, 'a': 1, 'r': 2, 'd': 3, 'u': 4, 'i': 5, 'c': 6}
+    absentdir = absentones(statlist[2], statlist[3])
+    finalrs = [[], [], [], [], [], [], []]
+    didsomethingchanged = False
+
+    for st in pycompat.bytestr(status):
+
+        try:
+            ind = indexes[st]
+        except KeyError:
+            raise error.Abort("Unable to parse the terse status, use marduic")
+
+        sfiles = statlist[ind]
+        if not sfiles:
+            continue
+        pardict = {}
+        for a in sfiles:
+            par = os.path.dirname(a)
+            try:
+                pardict[par].append(a)
+            except KeyError:
+                pardict[par] = [a]
+
+        rs = []
+        newls = []
+        for par in iter(pardict):
+            lenpar = numfiles(par)
+            if lenpar == len(pardict[par]):
+                newls.append(par)
+
+        if not newls:
+            continue
+
+        while newls:
+            newel = newls.pop()
+            if newel == '':
+                continue
+            parn = os.path.dirname(newel)
+            pardict[newel] = []
+            try:
+                pardict[parn].append(newel + pycompat.ossep)
+            except KeyError:
+                pardict[parn] = [newel + pycompat.ossep]
+            lenpar = numfiles(parn)
+            if lenpar == len(pardict[parn]):
+                newls.append(parn)
+
+        for par, files in pardict.iteritems():
+            rs.extend(files)
+
+        finalrs[ind] = rs
+        didsomethingchanged = True
+
+    # If nothing is changed, make sure the order of files is preserved.
+    if not didsomethingchanged:
+        return statlist
+
+    for x in xrange(7):
+        if not finalrs[x]:
+            finalrs[x] = statlist[x]
+
+    return finalrs
+
 def findpossible(cmd, table, strict=False):
     """
     Return cmd -> (aliases, command table entry)


More information about the Mercurial-devel mailing list