Patchwork D3439: templatefilters: add commonprefix

login
register
mail settings
Submitter phabricator
Date May 9, 2018, 10:53 p.m.
Message ID <28c1a5559b1234d52760feae60a4a601@localhost.localdomain>
Download mbox | patch
Permalink /patch/31437/
State Not Applicable
Headers show

Comments

phabricator - May 9, 2018, 10:53 p.m.
joerg.sonnenberger updated this revision to Diff 8595.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D3439?vs=8593&id=8595

REVISION DETAIL
  https://phab.mercurial-scm.org/D3439

AFFECTED FILES
  mercurial/templatefilters.py
  tests/test-template-filters.t

CHANGE DETAILS




To: joerg.sonnenberger, #hg-reviewers
Cc: yuja, mercurial-devel
Yuya Nishihara - May 10, 2018, 12:40 p.m.
> +  $ hg debugtemplate '{"foo/bar\nfoo/bar\n"|splitlines|commonprefix}\n'
> +  foo

should be "foo/bar"

> +  $ hg debugtemplate '{"/foo/bar\n/foo/bar\n"|splitlines|commonprefix}\n'
> +  foo

should be "/foo/bar"

> +  $ hg debugtemplate '{"/foo\n/foo\n"|splitlines|commonprefix}\n'
> +  

should e "/foo"

FWIW, I doubt if scanning all elements with the seen set is faster than
calling min()/max() to pick the farthest pair because Python is slow.

> {str|commonprefix} is not really interesting since it is naturally an
> iterable of text.

I think it's better to error out, but that could be addressed later.
phabricator - May 10, 2018, 12:40 p.m.
yuja added a comment.


  > +  $ hg debugtemplate '{"foo/bar\nfoo/bar\n"|splitlines|commonprefix}\n'
  >  +  foo
  
  should be "foo/bar"
  
  > +  $ hg debugtemplate '{"/foo/bar\n/foo/bar\n"|splitlines|commonprefix}\n'
  >  +  foo
  
  should be "/foo/bar"
  
  > +  $ hg debugtemplate '{"/foo\n/foo\n"|splitlines|commonprefix}\n'
  >  +
  
  should e "/foo"
  
  FWIW, I doubt if scanning all elements with the seen set is faster than
  calling min()/max() to pick the farthest pair because Python is slow.
  
  > {str|commonprefix} is not really interesting since it is naturally an
  >  iterable of text.
  
  I think it's better to error out, but that could be addressed later.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3439

To: joerg.sonnenberger, #hg-reviewers
Cc: yuja, mercurial-devel
Yuya Nishihara - June 3, 2018, 3:35 a.m.
For the record, I still believe the commonprefix of a pair of identical paths
should be the path itself as it is the longest sub-component of these paths.

> > +  $ hg debugtemplate '{"foo/bar\nfoo/bar\n"|splitlines|commonprefix}\n'
> > +  foo
> 
> should be "foo/bar"

And removing the leading slash is awkward.

> > +  $ hg debugtemplate '{"/foo/bar\n/foo/bar\n"|splitlines|commonprefix}\n'
> > +  foo
> 
> should be "/foo/bar"
phabricator - June 3, 2018, 3:35 a.m.
yuja added a comment.


  For the record, I still believe the commonprefix of a pair of identical paths
  should be the path itself as it is the longest sub-component of these paths.
  
  >> +  $ hg debugtemplate '{"foo/bar\nfoo/bar\n"|splitlines|commonprefix}\n'
  >  > +  foo
  > 
  > should be "foo/bar"
  
  And removing the leading slash is awkward.
  
  >> +  $ hg debugtemplate '{"/foo/bar\n/foo/bar\n"|splitlines|commonprefix}\n'
  >  > +  foo
  > 
  > should be "/foo/bar"

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3439

To: joerg.sonnenberger, #hg-reviewers
Cc: yuja, mercurial-devel

Patch

diff --git a/tests/test-template-filters.t b/tests/test-template-filters.t
new file mode 100644
--- /dev/null
+++ b/tests/test-template-filters.t
@@ -0,0 +1,23 @@ 
+  $ hg debugtemplate '{""|splitlines|commonprefix}\n'
+  
+  $ hg debugtemplate '{"foo/bar\nfoo/baz\nfoo/foobar\n"|splitlines|commonprefix}\n'
+  foo
+  $ hg debugtemplate '{"foo/bar\nfoo/bar\n"|splitlines|commonprefix}\n'
+  foo
+  $ hg debugtemplate '{"/foo/bar\n/foo/bar\n"|splitlines|commonprefix}\n'
+  foo
+  $ hg debugtemplate '{"/foo\n/foo\n"|splitlines|commonprefix}\n'
+  
+  $ hg debugtemplate '{"foo/bar\nbar/baz"|splitlines|commonprefix}\n'
+  
+  $ hg debugtemplate '{"foo/bar\nbar/baz\nbar/foo\n"|splitlines|commonprefix}\n'
+  
+  $ hg debugtemplate '{"foo/../bar\nfoo/bar"|splitlines|commonprefix}\n'
+  foo
+  $ hg debugtemplate '{"foo\n/foo"|splitlines|commonprefix}\n'
+  
+  $ hg init
+  $ hg log -r null -T '{rev|commonprefix}'
+  hg: parse error: argument is not a list of text
+  (template filter 'commonprefix' is not compatible with keyword 'rev')
+  [255]
diff --git a/mercurial/templatefilters.py b/mercurial/templatefilters.py
--- a/mercurial/templatefilters.py
+++ b/mercurial/templatefilters.py
@@ -7,6 +7,7 @@ 
 
 from __future__ import absolute_import
 
+import functools
 import os
 import re
 import time
@@ -99,6 +100,46 @@ 
     """
     return os.path.basename(path)
 
+@templatefilter('commonprefix')
+def commonprefix(filelist):
+    """List of text. Treats each list item as file name with /
+    as path separator and returns the longest common directory
+    prefix shared by all list items.
+    Returns the empty string if no common prefix exists.
+
+    The list items are not normalized, i.e. "foo/../bar" is handled as
+    file "bar" in the directory "foo/..". Leading slashes are ignored.
+
+    For example, ["foo/bar/baz", "foo/baz/bar"] becomes "foo" and
+    ["foo/bar", "baz"] becomes "".
+    """
+    seen = set()
+    def common(a, b):
+        if b in seen:
+            return a
+        seen.add(b)
+        if len(a) > len(b):
+            a = b[:len(a)]
+            seen.add(a)
+        elif len(b) > len(a):
+            b = b[:len(a)]
+            if b in seen:
+                return a
+            seen.add(b)
+        if a == b:
+            return a
+        for i in xrange(len(a)):
+            if a[i] != b[i]:
+                return a[:i]
+        return a
+    try:
+        if not filelist:
+            return ""
+        dirlist = [tuple(f.lstrip('/').split('/')[:-1]) for f in filelist]
+        return '/'.join(functools.reduce(common, dirlist))
+    except TypeError:
+        raise error.ParseError(_('argument is not a list of text'))
+
 @templatefilter('count')
 def count(i):
     """List or text. Returns the length as an integer."""