D3439: templatefilters: add commonprefix
yuja added a comment. > > `commondir()` would be fine as well. `commonpath()` doesn't feel better. I'm ambivalent about either nam> > I'd vote for changing it then. Both because I think it might make it clearer that it's the common prefix of "foo/bar" and "food" is not "foo" and because, as I said, we might want such a function later and it would be unfortunate if the name was taken. Btw, I just checked and we already have `dirname()` and `stripdir()` functions that would match `commondir()`. +1 for `commondir()`. It matches the actual behavior, which is the last filename part is always stripped. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D3439 To: joerg.sonnenberger, #hg-reviewers Cc: martinvonz, yuja, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: D3439: templatefilters: add commonprefix
> > `commondir()` would be fine as well. `commonpath()` doesn't feel better. > I'm ambivalent about either nam> > I'd vote for changing it then. Both because I think it might make it > clearer that it's the common prefix of "foo/bar" and "food" is not "foo" and > because, as I said, we might want such a function later and it would be > unfortunate if the name was taken. Btw, I just checked and we already have > `dirname()` and `stripdir()` functions that would match `commondir()`. +1 for `commondir()`. It matches the actual behavior, which is the last filename part is always stripped. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3439: templatefilters: add commonprefix
martinvonz added a comment. In https://phab.mercurial-scm.org/D3439#58410, @joerg.sonnenberger wrote: > In https://phab.mercurial-scm.org/D3439#58405, @martinvonz wrote: > > > Do you think we should call it `commonpath()` or `commondir()` instead in case we want `commonprefix()` to work for any string in the future (and not care about path separators)? > > > `commondir()` would be fine as well. `commonpath()` doesn't feel better. I'm ambivalent about either name. I'd vote for changing it then. Both because I think it might make it clearer that it's the common prefix of "foo/bar" and "food" is not "foo" and because, as I said, we might want such a function later and it would be unfortunate if the name was taken. Btw, I just checked and we already have `dirname()` and `stripdir()` functions that would match `commondir()`. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D3439 To: joerg.sonnenberger, #hg-reviewers Cc: martinvonz, yuja, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3439: templatefilters: add commonprefix
joerg.sonnenberger added a comment. In https://phab.mercurial-scm.org/D3439#58405, @martinvonz wrote: > Do you think we should call it `commonpath()` or `commondir()` instead in case we want `commonprefix()` to work for any string in the future (and not care about path separators)? `commondir()` would be fine as well. `commonpath()` doesn't feel better. I'm ambivalent about either name. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D3439 To: joerg.sonnenberger, #hg-reviewers Cc: martinvonz, yuja, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3439: templatefilters: add commonprefix
martinvonz added a comment. Do you think we should call it `commonpath()` or `commondir()` instead in case we want `commonprefix()` to work for any string in the future (and not care about path separators)? REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D3439 To: joerg.sonnenberger, #hg-reviewers Cc: martinvonz, yuja, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: D3439: templatefilters: add commonprefix
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" ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3439: templatefilters: add commonprefix
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 ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3439: templatefilters: add commonprefix
This revision was automatically updated to reflect the committed changes. Closed by commit rHG56dd15178190: templatefilters: add commonprefix (authored by joerg.sonnenberger, committed by ). CHANGED PRIOR TO COMMIT https://phab.mercurial-scm.org/D3439?vs=8614=8946#toc REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3439?vs=8614=8946 REVISION DETAIL https://phab.mercurial-scm.org/D3439 AFFECTED FILES mercurial/templatefilters.py tests/test-template-filters.t CHANGE DETAILS 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 @@ -99,6 +99,45 @@ """ 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 "". +""" +def common(a, b): +if len(a) > len(b): +a = b[:len(a)] +elif len(b) > len(a): +b = b[:len(a)] +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 = [f.lstrip('/').split('/')[:-1] for f in filelist] +if len(dirlist) == 1: +return '/'.join(dirlist[0]) +a = min(dirlist) +b = max(dirlist) +# The common prefix of a and b is shared with all +# elements of the list since Python sorts lexicographical +# and [1, x] after [1]. +return '/'.join(common(a, b)) +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.""" To: joerg.sonnenberger, #hg-reviewers Cc: yuja, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3439: templatefilters: add commonprefix
joerg.sonnenberger updated this revision to Diff 8614. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3439?vs=8595=8614 REVISION DETAIL https://phab.mercurial-scm.org/D3439 AFFECTED FILES mercurial/templatefilters.py tests/test-template-filters.t CHANGE DETAILS 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,45 @@ """ 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 "". +""" +def common(a, b): +if len(a) > len(b): +a = b[:len(a)] +elif len(b) > len(a): +b = b[:len(a)] +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 = [f.lstrip('/').split('/')[:-1] for f in filelist] +if len(dirlist) == 1: +return '/'.join(dirlist[0]) +a = min(dirlist) +b = max(dirlist) +# The common prefix of a and b is shared with all +# elements of the list since Python sorts lexicographical +# and [1, x] after [1]. +return '/'.join(common(a, b)) +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.""" To: joerg.sonnenberger, #hg-reviewers Cc: yuja, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: D3439: templatefilters: add commonprefix
> + $ 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. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3439: templatefilters: add commonprefix
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 ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3439: templatefilters: add commonprefix
joerg.sonnenberger updated this revision to Diff 8595. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3439?vs=8593=8595 REVISION DETAIL https://phab.mercurial-scm.org/D3439 AFFECTED FILES mercurial/templatefilters.py tests/test-template-filters.t CHANGE DETAILS 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.""" To: joerg.sonnenberger, #hg-reviewers Cc: yuja, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3439: templatefilters: add commonprefix
joerg.sonnenberger added a comment. {str|commonprefix} is not really interesting since it is naturally an iterable of text. The others are covered, the routine tries to optimize a couple of common cases as well now. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D3439 To: joerg.sonnenberger, #hg-reviewers Cc: yuja, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3439: templatefilters: add commonprefix
joerg.sonnenberger updated this revision to Diff 8593. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3439?vs=8590=8593 REVISION DETAIL https://phab.mercurial-scm.org/D3439 AFFECTED FILES mercurial/templatefilters.py tests/test-template-filters.t CHANGE DETAILS 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,21 @@ + $ hg debugtemplate '{""|splitlines|commonprefix}\n' + + $ hg debugtemplate '{"foo/bar\nfoo/baz\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\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,38 @@ """ 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 = b, 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.""" To: joerg.sonnenberger, #hg-reviewers Cc: yuja, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3439: templatefilters: add commonprefix
yuja added a comment. Please add tests of edge cases. - `str|commonprefix` - infinite loop (e.g. `["/foo", "bar"]`) - exact match (e.g. `["/foo"]` and `["/foo", "/foo"]`) - empty list `os.path.commonprefix()` will provide some hints to avoid comparison of all list elements by using min()/max(). REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D3439 To: joerg.sonnenberger, #hg-reviewers Cc: yuja, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: D3439: templatefilters: add commonprefix
Please add tests of edge cases. - `str|commonprefix` - infinite loop (e.g. `["/foo", "bar"]`) - exact match (e.g. `["/foo"]` and `["/foo", "/foo"]`) - empty list `os.path.commonprefix()` will provide some hints to avoid comparison of all list elements by using min()/max(). ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3439: templatefilters: add commonprefix
joerg.sonnenberger updated this revision to Diff 8590. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3439?vs=8549=8590 REVISION DETAIL https://phab.mercurial-scm.org/D3439 AFFECTED FILES mercurial/templatefilters.py tests/test-template-filters.t CHANGE DETAILS 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,11 @@ + $ hg debugtemplate '{"foo/bar\nfoo/baz\n"|splitlines|commonprefix}\n' + foo + $ hg debugtemplate '{"foo/bar\nbar/baz"|splitlines|commonprefix}\n' + + $ hg debugtemplate '{"foo/../bar\nfoo/bar"|splitlines|commonprefix}\n' + foo + $ 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,33 @@ """ return os.path.basename(path) +@templatefilter('commonprefix') +def commonprefix(filelist): +"""List of text. Treats each list item as file name, 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/..". + +For example, ["foo/bar/baz", "foo/baz/bar"] becomes "foo" and +["foo/bar", "baz"] becomes "". +""" +def common(a, b): +while a != b: +if len(a) > len(b): +a = os.path.dirname(a) +else: +b = os.path.dirname(b) +return a +try: +if not filelist: +return "" +dirlist = [os.path.dirname(f) for f in filelist] +return 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.""" To: joerg.sonnenberger, #hg-reviewers Cc: yuja, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3439: templatefilters: add commonprefix
joerg.sonnenberger updated this revision to Diff 8549. joerg.sonnenberger retitled this revision from "template filters: add commonprefix" to "templatefilters: add commonprefix". REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3439?vs=8454=8549 REVISION DETAIL https://phab.mercurial-scm.org/D3439 AFFECTED FILES mercurial/templatefilters.py tests/test-template-filters.t CHANGE DETAILS 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,11 @@ + $ hg debugtemplate '{"foo/bar\nfoo/baz\n"|splitlines|commonprefix}\n' + foo + $ hg debugtemplate '{"foo/bar\nbar/baz"|splitlines|commonprefix}\n' + + $ hg debugtemplate '{"foo/../bar\nfoo/bar"|splitlines|commonprefix}\n' + foo + $ 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 @@ -99,6 +99,33 @@ """ return os.path.basename(path) +@templatefilter('commonprefix') +def commonprefix(filelist): +"""List of text. Treats each list item as file name, 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/..". + +For example, ["foo/bar/baz", "foo/baz/bar"] becomes "foo" and +["foo/bar", "baz"] becomes "". +""" +def common(a, b): +while a != b: +if len(a) > len(b): +a = os.path.dirname(a) +else: +b = os.path.dirname(b) +return a +try: +if not filelist: +return "" +dirlist = [os.path.dirname(f) for f in filelist] +return 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.""" To: joerg.sonnenberger, #hg-reviewers Cc: yuja, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel