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

Denis Laxalde denis at laxalde.org
Sat Jun 17 04:23:06 EDT 2017


Pulkit Goyal a écrit :
> # 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.

Thanks for working on this!

I wonder if this tersestatus function couldn't be unit-tested (might be
easier if it didn't need the "repo" argument). I'd make it easier to
understand its behaviour I think.

A couple of remarks (mostly style) below.

> 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

Could you use os.path.join() ?

> +        for f in os.listdir(abspath):
> +            if not match(f):
> +                lendir += 1
> +        if absentdir.get(dirname):
> +            lendir += absentdir[dirname]

Python nit: `if dict.get(key):` is better written as `if key in dict:`.
Here, you could also have written `lendir += absentdir.get(dirname, 0)`
and drop the 'if'.

> +        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 = [[], [], [], [], [], [], []]

is it `finalrs = [[]] * len(indexes)` ?

> +    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")

What's "marduic"?
Also, is it really an user error? If not an assertion might be better maybe.

> +
> +        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]

Other python nit: `pardict.setdefault(par, []).append(a)` to replace the
try/except block.

> +
> +        rs = []
> +        newls = []
> +        for par in iter(pardict):

iteritems() since you further need the value (pardict[par])

> +            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]

setdefault could be used here as well.
Also, why the `+ pycompat.ossep`? Might be worth adding a comment.

> +            lenpar = numfiles(parn)
> +            if lenpar == len(pardict[parn]):
> +                newls.append(parn)
> +
> +        for par, files in pardict.iteritems():

iteritems() -> itervalues(), since "par" is not used.

> +            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]

for rs in finalrs:
   if not rs:
      rs[:] = statlist[x]

> +
> +    return finalrs
> +
>  def findpossible(cmd, table, strict=False):
>      """
>      Return cmd -> (aliases, command table entry)
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
>



More information about the Mercurial-devel mailing list