[PATCH] locate: add support for filtering by file type

Bryan O'Sullivan bos at serpentine.com
Tue Apr 2 15:33:40 CDT 2013


# HG changeset patch
# User Bryan O'Sullivan <bryano at fb.com>
# Date 1364934784 25200
#      Tue Apr 02 13:33:04 2013 -0700
# Node ID d13118dd5f087467e5edf4e6752ac3110ee21475
# Parent  65a67c7aefed9d86aa24758aaa7529445856db9f
locate: add support for filtering by file type

This makes it possible to say "show me matches that are not symlinks"
via "-t x -t f", and so on.

diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -3814,6 +3814,7 @@ def init(ui, dest=".", **opts):
 
 @command('locate',
     [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
+    ('t', 'type', [], _('only print files of the given type'), _('TYPE')),
     ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
     ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
     ] + walkopts,
@@ -3831,6 +3832,15 @@ def locate(ui, repo, *pats, **opts):
     If no patterns are given to match, this command prints the names
     of all files under Mercurial control in the working directory.
 
+    To look for particular types of file, specify one or more "--type"
+    arguments:
+
+    - "symlink" or "l": symbolic links
+
+    - "executable", "exe", or "x": executable files
+
+    - "plain" or "f": plain files (not executable, not symlinks)
+
     If you want to feed the output of this command into the "xargs"
     command, use the -0 option to both this command and "xargs". This
     will avoid the problem of "xargs" treating single filenames that
@@ -3841,12 +3851,26 @@ def locate(ui, repo, *pats, **opts):
     end = opts.get('print0') and '\0' or '\n'
     rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
 
+    typenames = dict(symlink='l', l='l',
+                     plain='', f='',
+                     executable='x', exe='x', x='x')
+    try:
+        types = set(typenames[t] for t in opts.get('type'))
+    except KeyError, err:
+        raise util.Abort(_('unknown file type: %s') % err)
+    if not types or types == set(typenames.itervalues()):
+        # match all file types
+        types = None
+
     ret = 1
-    m = scmutil.match(repo[rev], pats, opts, default='relglob')
+    ctx = repo[rev]
+    m = scmutil.match(ctx, pats, opts, default='relglob')
     m.bad = lambda x, y: False
     for abs in repo[rev].walk(m):
         if not rev and abs not in repo.dirstate:
             continue
+        if types and ctx[abs].flags() not in types:
+            continue
         if opts.get('fullpath'):
             ui.write(repo.wjoin(abs), end)
         else:
diff --git a/tests/test-locate.t b/tests/test-locate.t
--- a/tests/test-locate.t
+++ b/tests/test-locate.t
@@ -1,10 +1,12 @@
   $ hg init repo
   $ cd repo
   $ echo 0 > a
+  $ chmod +x a
   $ echo 0 > b
   $ echo 0 > t.h
   $ mkdir t
   $ echo 0 > t/x
+  $ chmod +x t/x a
   $ echo 0 > t/b
   $ echo 0 > t/e.h
   $ mkdir dir.h
@@ -23,6 +25,20 @@
 
   $ hg locate a
   a
+  $ hg locate -t x -t l a
+  a
+
+  $ hg locate -t x
+  a
+  t/x
+
+  $ ln -s wibble symlink
+  $ hg add symlink
+  $ hg locate -t l
+  symlink
+  $ hg locate -t f symlink
+  [1]
+  $ hg forget symlink
 
   $ hg locate NONEXISTENT
   [1]


More information about the Mercurial-devel mailing list