Fix recursive exclude Issue #114 - #115
Conversation
|
Thanks for this PR. Sorry about #96, I just was not active merging open PRs since then. |
There was a problem hiding this comment.
This change needs a lot more explaining. The elements of _excludes are already globbed, so "foo/*" would become a list of files in folder foo. I assume what you are trying to achieve is a recursive globbing, as commonly requested here https://stackoverflow.com/questions/2186525. As in the answers there, it seems the current code would already to the right thing starting with python3.5 and an exclude like --exclude="third_party/**/*" (I have not tried it). Even if that did not work, the correct approach here would likely be to either fix the globbing, or to use a robust path/subpath identification (not string.startswith)
There was a problem hiding this comment.
As in the answers there, it seems the current code would already to the right thing starting with python3.5 and an exclude like --exclude="third_party/**/*" (I have not tried it).
I did try it, multiple ways. It doesn't work. Hence the fix. The idea here is to exclude an entire subdirectory, not each individual file within that subdirectory.
Here is a simple test that you can run on the current tree:
./cpplint.py --recursive --exclude='sample/boost-sample/**/*' samples 2>&1 |fgrep boost-sample
If it returns output , your code is broken. I tested it on both python 3.5.2 (Ubuntu 16.04 LTS) and python 3.6.9 (Ubuntu 18.04 LTS).
There was a problem hiding this comment.
ok, in that case something safer than string startswith would be acceptable. If the user excludes folder /foo, we should not exclude folder /foobar.
In another project I used this snippet:
def _is_parent_path(parent, child):
"""Return true if child is subdirectory of parent.
Assumes both paths are absolute and don't contain symlinks.
"""
parent = os.path.normpath(parent)
child = os.path.normpath(child)
prefix = os.path.commonprefix([parent, child])
if prefix == parent:
# Note: os.path.commonprefix operates on character basis, so
# take extra care of situations like '/foo/ba' and '/foo/bar/baz'
child_suffix = child[len(prefix):]
child_suffix = child_suffix.lstrip(os.sep)
if child == os.path.join(prefix, child_suffix):
return True
return False
There was a problem hiding this comment.
I have done more testing by copying boost-sample to boost-sample2 (to simulate foobar vs foobaz). If I run:
./cpplint.py --recursive --exclude='samples/boost-sample' samples 2>&1 |fgrep boost
it excludes both. But, if I run:
./cpplint.py --recursive --exclude='samples/boost-sample/*' samples 2>&1 |fgrep boost
It only excludes boost-sample, not boost-sample2.
I also tried with --exclude='boost-sample', in which case both paths were included. So it really is up to the user to properly terminate the exclude string.
For your example, '--exclude=/foo' would in fact get /foo, /foobar. /foobaz, etc. but if they type '--exclude=/foo/*' it would not exclude /foobar or /foobaz.
|
Updated to fix merge conflicts. |
|
Do you see any issue with merging #124 instead? I can see that with your simple solution, the foo/foobar problem can be worked around, but I would prefer no workaround to be necessary for backward compatible behavior. |
|
Aaah, wrong branch! |
I fixed the --exclude issue and added a new testcase for cpplint_clitest.py. Tested, works.