[PATCH V2] status: add terse option flag (issue4119)

Ryan McElroy rm at fb.com
Wed Oct 14 17:40:35 CDT 2015


On 10/14/2015 7:20 AM, Pierre-Yves David wrote:
>
>
> On 10/13/2015 02:46 PM, Sean Farley wrote:
>> # HG changeset patch
>> # User Sean Farley <sean at farley.io>
>> # Date 1427261050 25200
>> #      Tue Mar 24 22:24:10 2015 -0700
>> # Node ID 93173ffbe421307efe9cae4404587a541a826ee7
>> # Parent  a38924f7680c6b7d95e14ade999c35748c9dcafd
>> status: add terse option flag (issue4119)
>
> I really like the idea and think we should move forward on this topic. 
> However there is likely some testing and discussion required. Can we 
> flag the command switch as EXPERIMENTAL so that we have option to 
> adjust this in the next cycle?
>
>>
>> Based on an idea by Martin Geisler, this patch adds the ability to 
>> abbreviate
>> the ouput of status by only listing the parent directory for multiple 
>> files. By
>> default, we do this for all status types but control this through the
>> experimental.terse option.
>>
>> Future work could speed up status operations even further by skipping 
>> disk
>> operations based on this config.
>>
>> For example, imagine we have the following output of status:
>>
>> $ hg st
>> A mercurial/adddir/a
>> A mercurial/adddir/b
>> A mercurial/adddir/c
>> ? bar
>> ? baz
>> ? foo/subdir/a
>> ? foo/subdir/b
>> ? foo/subdir/c
>> ? foo/x
>> ? foo/y
>> ? mercurial/subdir/a
>> ? mercurial/subdir/b
>> ? mercurial/subdir/c
>> ? ugh/x
>>
>> without any configuration, we get:
>>
>> $ hg st -t
>> A mercurial/adddir/
>> ? bar
>> ? baz
>> ? foo/
>> ? mercurial/subdir/
>> ? ugh/x
Why do we get ugh/x and not just ugh/ ?

If not all files in  mercurial/adddir/a was not added (ie, only some 
files were added, what does the output look like?)

>>
>> and with some config knobs, we get:
>>
>> $ hg st -t --config experimental.terse='?'

This config option is poorly named -- I have no idea what to expect it 
to do (I had to read the code).

Perhaps better: experimental.tersestatuses='?'

>> A mercurial/adddir/a
>> A mercurial/adddir/b
>> A mercurial/adddir/c
>> ? bar
>> ? baz
>> ? foo/
>> ? mercurial/subdir/
>> ? ugh/x
>>
>> And we can still see the files in 'foo' by:
>>
>> $ hg st -t foo
>> ? foo/subdir/
>> ? foo/x
>> ? foo/y
>>
>> But, this has a downside of not working as desired with relative paths:
>>
>> $ hg st -t re:
>> A mercurial/adddir/a
>> A mercurial/adddir/b
>> A mercurial/adddir/c
>> ? bar
>> ? baz
>> ? foo/subdir/a
>> ? foo/subdir/b
>> ? foo/subdir/c
>> ? foo/x
>> ? foo/y
>> ? mercurial/subdir/a
>> ? mercurial/subdir/b
>> ? mercurial/subdir/c
>> ? ugh/x

What about for the '' filematcher? (eg, hg status ''). Does that also 
fail to be tersified?

What would it take to make this work?

>>
>> diff --git a/mercurial/commands.py b/mercurial/commands.py
>> --- a/mercurial/commands.py
>> +++ b/mercurial/commands.py
>> @@ -21,10 +21,11 @@ import minirst, revset, fileset
>>   import dagparser, context, simplemerge, graphmod, copies
>>   import random, operator
>>   import setdiscovery, treediscovery, dagutil, pvec, localrepo
>>   import phases, obsolete, exchange, bundle2, repair, lock as lockmod
>>   import ui as uimod
>> +import match as matchmod
>>
>>   table = {}
>>
>>   command = cmdutil.command(table)
>>
>> @@ -5898,10 +5899,11 @@ class httpservice(object):
>>       ('n', 'no-status', None, _('hide status prefix')),
>>       ('C', 'copies', None, _('show source of copied files')),
>>       ('0', 'print0', None, _('end filenames with NUL, for use with 
>> xargs')),
>>       ('', 'rev', [], _('show difference from revision'), _('REV')),
>>       ('', 'change', '', _('list the changed files of a revision'), 
>> _('REV')),
>> +    ('t', 'terse', None, _('show only directory of unknown files')),
>>       ] + walkopts + subrepoopts + formatteropts,
>>       _('[OPTION]... [FILE]...'),
>>       inferrepo=True)
>>   def status(ui, repo, *pats, **opts):
>>       """show changed files in the working directory
>> @@ -5998,10 +6000,65 @@ def status(ui, repo, *pats, **opts):
>>
>>       m = scmutil.match(repo[node2], pats, opts)
>>       stat = repo.status(node1, node2, m,
>>                          'ignored' in show, 'clean' in show, 
>> 'unknown' in show,
>>                          opts.get('subrepos'))
>> +
>> +    if opts.get('terse'):
>> +        stat = list(stat)
>> +        statmap = dict(zip('MAR!?IC', range(len('MAR!?IC'))))
>> +        knowndirs = set([''])
>> +
>> +        # can we avoid walking everything?
>> +        for path in repo.unfiltered()['.']:
>> +            d = os.path.dirname(path)
>> +            while d not in knowndirs:
>> +                knowndirs.add(d)
>> +                d = os.path.dirname(d)
>> +
>> +        match = None
>> +        if pats:
>> +            match = matchmod.match(repo.root, cwd, pats, 
>> opts.get('include'),
>> +                                   opts.get('exclude'))
>> +
>> +        # this method exists to override hiding a subdirectory if it 
>> matches
>> +        # one of the *pats, e.g.:
>> +        # hg st -t foo
>> +        # foo/a
>> +        # foo/b
>> +        def _match(path):
>> +            ret = path not in knowndirs
>> +            if match is not None:
>> +                ret = ret and not match(path)
>> +            return ret
>> +
>> +        for s in ui.config('experimental', 'terse', 'MAR!?IC').upper():
>> +            results = {}
>> +            for path in stat[statmap[s]]:
>> +                prev = path
>> +                d = os.path.dirname(prev)
>> +                while _match(d):
>> +                    prev = d
>> +                    d = os.path.dirname(prev)
>> +
>> +                # to get the behavior of displaying the full path if 
>> there is
>> +                # only one file, we add the resulting path to a 
>> dictionary and
>> +                # overwrite that value if it already existed.
>> +                if prev != path:
>> +                    prev += '/'
>> +                    res = results.get(prev)
>> +                    if res is None:
>> +                        results[prev] = path
>> +                    else:
>> +                        results[prev] = prev
>> +                else:
>> +                    results[prev] = path
>> +
>> +            # replace the previous list
>> +            stat[statmap[s]] = sorted(results.values())
>> +        stat = scmutil.status(*stat)
>> +
>>       changestates = zip(states, 'MAR!?IC', stat)
>>
>>       if (opts.get('all') or opts.get('copies')
>>           or ui.configbool('ui', 'statuscopies')) and not 
>> opts.get('no_status'):
>>           copy = copies.pathcopies(repo[node1], repo[node2], m)
>> diff --git a/tests/test-completion.t b/tests/test-completion.t
>> --- a/tests/test-completion.t
>> +++ b/tests/test-completion.t
>> @@ -214,11 +214,11 @@ Show all commands + options
>>     merge: force, rev, preview, tool
>>     pull: update, force, rev, bookmark, branch, ssh, remotecmd, insecure
>>     push: force, rev, bookmark, branch, new-branch, ssh, remotecmd, 
>> insecure
>>     remove: after, force, subrepos, include, exclude
>>     serve: accesslog, daemon, daemon-pipefds, errorlog, port, 
>> address, prefix, name, web-conf, webdir-conf, pid-file, stdio, 
>> cmdserver, templates, style, ipv6, certificate
>> -  status: all, modified, added, removed, deleted, clean, unknown, 
>> ignored, no-status, copies, print0, rev, change, include, exclude, 
>> subrepos, template
>> +  status: all, modified, added, removed, deleted, clean, unknown, 
>> ignored, no-status, copies, print0, rev, change, terse, include, 
>> exclude, subrepos, template
>>     summary: remote
>>     update: clean, check, date, rev, tool
>>     addremove: similarity, subrepos, include, exclude, dry-run
>>     archive: no-decode, prefix, rev, type, subrepos, include, exclude
>>     backout: merge, commit, parent, rev, edit, tool, include, 
>> exclude, message, logfile, date, user
>> diff --git a/tests/test-help.t b/tests/test-help.t
>> --- a/tests/test-help.t
>> +++ b/tests/test-help.t
>> @@ -575,10 +575,11 @@ Test command without options
>>      -n --no-status           hide status prefix
>>      -C --copies              show source of copied files
>>      -0 --print0              end filenames with NUL, for use with xargs
>>         --rev REV [+]         show difference from revision
>>         --change REV          list the changed files of a revision
>> +   -t --terse               show only directory of unknown files
>>      -I --include PATTERN [+] include names matching the given patterns
>>      -X --exclude PATTERN [+] exclude names matching the given patterns
>>      -S --subrepos            recurse into subrepositories
>>
>>     (some details hidden, use --verbose to show complete help)
>> diff --git a/tests/test-status.t b/tests/test-status.t
>> --- a/tests/test-status.t
>> +++ b/tests/test-status.t
>> @@ -99,10 +99,32 @@ hg status . in repo root:
>>     $ hg status --cwd b/2 ..
>>     ? ../1/in_b_1
>>     ? in_b_2
>>     ? ../in_b
>>
>> +test status with terse
>> +
>> +  $ hg status --terse
>> +  ? a/
>> +  ? b/
>> +  ? in_root
>> +
>> +make sure we can still list the individual files by specifying the 
>> directory
>> +
>> +  $ hg status --terse a
>> +  ? a/1/in_a_1
>> +  ? a/in_a
>> +
>> +test all status modes, not just unknown files, with terse
>> +
>> +  $ hg add -q a
>> +  $ hg status --terse --config experimental.terse='MAR!?IC'
>> +  A a/
>> +  ? b/
>> +  ? in_root
>> +  $ hg forget -q a
>> +
>>   combining patterns with root and patterns without a root works
>>
>>     $ hg st a/in_a re:.*b$
>>     ? a/in_a
>>     ? b/in_b
>> _______________________________________________
>> Mercurial-devel mailing list
>> Mercurial-devel at selenic.com
>> https://selenic.com/mailman/listinfo/mercurial-devel
>>
>



More information about the Mercurial-devel mailing list