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

login
register
mail settings
Submitter Pulkit Goyal
Date June 14, 2017, 9:02 p.m.
Message ID <622220c3eb0a6ae2f0e7.1497474158@workspace>
Download mbox | patch
Permalink /patch/21379/
State Changes Requested
Headers show

Comments

Pulkit Goyal - June 14, 2017, 9:02 p.m.
# HG changeset patch
# User Pulkit Goyal <7895pulkit@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.
Pulkit Goyal - June 15, 2017, 2:06 p.m.
On Thu, Jun 15, 2017 at 2:32 AM, Pulkit Goyal <7895pulkit@gmail.com> wrote:
> # HG changeset patch
> # User Pulkit Goyal <7895pulkit@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):

While testing more, I found that this can raise OSError if the abspath
is a directory which is removed or deleted. I will include that in a
v2 if required or else do a followup.
Denis Laxalde - June 17, 2017, 8:23 a.m.
Pulkit Goyal a écrit :
> # HG changeset patch
> # User Pulkit Goyal <7895pulkit@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@mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
>
Pulkit Goyal - June 17, 2017, 2:34 p.m.
> 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.

Okay in that case, I will need to pass two other arguments for
repo.root and repo.dirstate._ignore as root and ignorefn respectively.
Or you mean to say not using them?
>
> A couple of remarks (mostly style) below.

Thanks for them, I will follow all of them in V2.
>
>> 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.

I am not sure what a good user error will be. I am changing it to
("'%s' not recognized" % st) in V2.
>
>> +
>> +        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]

In this case 'x' won't be defined. So can't use this.
>
>> +
>> +    return finalrs
>> +
>>  def findpossible(cmd, table, strict=False):
>>      """
>>      Return cmd -> (aliases, command table entry)
>> _______________________________________________
>> Mercurial-devel mailing list
>> Mercurial-devel@mercurial-scm.org
>> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
>>
>
Denis Laxalde - June 17, 2017, 4:11 p.m.
Pulkit Goyal a écrit :
>> 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.
>
> Okay in that case, I will need to pass two other arguments for
> repo.root and repo.dirstate._ignore as root and ignorefn respectively.
> Or you mean to say not using them?

If you need data, pass them to the function. Having two arguments with a
defined purpose is probably clearer/safer than one "repo" argument on
which you can basically do anything.

>>
>> A couple of remarks (mostly style) below.
>
> Thanks for them, I will follow all of them in V2.
>>
>>> 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.
>
> I am not sure what a good user error will be. I am changing it to
> ("'%s' not recognized" % st) in V2.

I mean: is it really a user error (i.e. something the user can solve)?
Or is it an assertion of the algorithm? In the former case,
error.Abort() is fine. Otherwise, it's misleading as it would give the
impression that the user did something wrong.

>>
>>> +
>>> +        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]
>
> In this case 'x' won't be defined. So can't use this.

Correct. So `for x, rs in enumerate(finalrs):` would work I think.

>>
>>> +
>>> +    return finalrs
>>> +
>>>  def findpossible(cmd, table, strict=False):
>>>      """
>>>      Return cmd -> (aliases, command table entry)
>>> _______________________________________________
>>> Mercurial-devel mailing list
>>> Mercurial-devel@mercurial-scm.org
>>> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
>>>
>>
Augie Fackler - June 17, 2017, 7:01 p.m.
> On Jun 17, 2017, at 12:11, Denis Laxalde <denis@laxalde.org> wrote:
> 
> Pulkit Goyal a écrit :
>>> 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.
>> 
>> Okay in that case, I will need to pass two other arguments for
>> repo.root and repo.dirstate._ignore as root and ignorefn respectively.
>> Or you mean to say not using them?
> 
> If you need data, pass them to the function. Having two arguments with a
> defined purpose is probably clearer/safer than one "repo" argument on
> which you can basically do anything.

I haven't looked at the code, but this is generally good architectural advice. I don't know that I'd block taking the patches on that though.

Will try to look these through in the next couple of days.

(It'd be nice if we could have more unit tests in hg and not *have* to test everything with functional tests - in theory we should be able to get equivalent coverage without doing nearly so much disk IO. We've historically been bad about even trying to move the needle.)

Patch

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)