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

Augie Fackler raf at durin42.com
Thu Oct 15 08:50:36 CDT 2015


On Wed, Oct 14, 2015 at 11:24:37PM -0700, 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 3dd7ff9879636256252dd87ddda204383fb5863e
> # Parent  a38924f7680c6b7d95e14ade999c35748c9dcafd
> status: add terse option flag (issue4119)

I'm +1 on this for this cycle, but would like others to chime in as I
know this has been contentious in the past.

(One thing I know this will need eventually is a way to disable it,
probably along the lines of --terse=never or something.)

>
> 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.
> Directories that only contain one file are not collapsed, though. By default,
> we do this for all status types but control this through the
> experimental.tersestatuses 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
>
> and with some config knobs, we get:
>
> $ hg st -t --config 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
>
> 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 (EXPERIMENTAL)')),
>      ] + 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', 'tersestatuses', '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-status.t b/tests/test-status.t
> --- a/tests/test-status.t
> +++ b/tests/test-status.t
> @@ -99,10 +99,40 @@ 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
> +  A a/
> +  ? b/
> +  ? in_root
> +
> +test config option to terse-ify just unknown files
> +
> +  $ hg status --terse --config experimental.tersestatuses='?'
> +  A a/1/in_a_1
> +  A a/in_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