Skip to content

Commit

Permalink
cpplint --root: support non-subdirectories
Browse files Browse the repository at this point in the history
Using cpplint.py --root with directories at a more outer level
will now prepend the header guard with all the directories from the
root to the file.

For example given

  ls /a/b/c # /a/b/c/.git /a/b/c/filename.h
  cpplint.py --root=/a/b /a/b/c/filename.h   # C_FILENAME_H_

  # no root behavior:
  cpplint.py /a/b/c/filename.h               # FILENAME_H_

Also supports relative paths:

  cd /a/b/c
  cpplint.py --root=.. filename.h            # C_FILENAME_H_

Note that the old usage is still supported:

  cd /a/b/c
  mkdir -p d/e/f
  touch /a/b/c/d/e/f/filename.h
  cpplint.py --root=d/e/f d/e/f/filename.h   # FILENAME_H_

which would "strip" the prefix rather than prepend an extra prefix.

(Invalid root prefixes are as before also ignored)
  • Loading branch information
iam committed Nov 8, 2017
1 parent ec88ff9 commit e7ddd2a
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 7 deletions.
64 changes: 57 additions & 7 deletions cpplint/cpplint.py
Original file line number Diff line number Diff line change
Expand Up @@ -1754,6 +1754,30 @@ def GetIndentLevel(line):
else:
return 0

def PathSplitToList(path):
"""Returns the path split into a list by the separator.
Args:
path: An absolute or relative path (e.g. '/a/b/c/' or '../a')
Returns:
A list of path components (e.g. ['a', 'b', 'c]).
"""
lst = []
while True:
(head, tail) = os.path.split(path)
if head == path: # absolute paths end
lst.append(head)
break
if tail == path: # relative paths end
lst.append(tail)
break

path = head
lst.append(tail)

lst.reverse()
return lst

def GetHeaderGuardCPPVariable(filename):
"""Returns the CPP variable that should be used as a header guard.
Expand All @@ -1776,13 +1800,39 @@ def GetHeaderGuardCPPVariable(filename):

fileinfo = FileInfo(filename)
file_path_from_root = fileinfo.RepositoryName()
if _root:
suffix = os.sep
# On Windows using directory separator will leave us with
# "bogus escape error" unless we properly escape regex.
if suffix == '\\':
suffix += '\\'
file_path_from_root = re.sub('^' + _root + suffix, '', file_path_from_root)

def FixupPathFromRoot():
# Process the file path with the --root flag if it was set.
if not _root:
return file_path_from_root

def StripListPrefix(lst, prefix):
# f(['x', 'y'], ['w, z']) -> None (not a valid prefix)
if lst[:len(prefix)] != prefix:
return None
# f(['a, 'b', 'c', 'd'], ['a', 'b']) -> ['c', 'd']
return lst[(len(prefix)):]

# root behavior:
# --root=subdir , lstrips subdir from the header guard
maybe_path = StripListPrefix(PathSplitToList(file_path_from_root),
PathSplitToList(_root))
if maybe_path:
return os.path.join(*maybe_path)

# --root=.. , will prepend the outer directory to the header guard
full_path = fileinfo.FullName()
root_abspath = os.path.abspath(_root)

maybe_path = StripListPrefix(PathSplitToList(full_path),
PathSplitToList(root_abspath))
if maybe_path:
return os.path.join(*maybe_path)

# --root=FAKE_DIR is ignored
return file_path_from_root

file_path_from_root = FixupPathFromRoot()
return re.sub(r'[^a-zA-Z0-9]', '_', file_path_from_root).upper() + '_'


Expand Down
51 changes: 51 additions & 0 deletions cpplint/cpplint_unittest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4232,6 +4232,12 @@ def testBuildHeaderGuardWithRoot(self):

self.assertEquals('CPPLINT_CPPLINT_TEST_HEADER_H_',
cpplint.GetHeaderGuardCPPVariable(file_path))
#
# test --root flags:
# this changes the cpp header guard prefix
#

# left-strip the header guard by using a root dir inside of the repo dir.
cpplint._root = 'cpplint'
self.assertEquals('CPPLINT_TEST_HEADER_H_',
cpplint.GetHeaderGuardCPPVariable(file_path))
Expand All @@ -4240,6 +4246,51 @@ def testBuildHeaderGuardWithRoot(self):
self.assertEquals('CPPLINT_CPPLINT_TEST_HEADER_H_',
cpplint.GetHeaderGuardCPPVariable(file_path))

# prepend to the header guard by using a root dir that is more outer
# than the repo dir

# (using absolute paths)
this_files_path = os.path.dirname(os.path.abspath(__file__))
(styleguide_path, this_files_dir) = os.path.split(this_files_path)
(styleguide_parent_path, _) = os.path.split(styleguide_path)
# parent dir of styleguide
cpplint._root = styleguide_parent_path
self.assertIsNotNone(styleguide_parent_path)
# do not have 'styleguide' repo in '/'
self.assertEquals('STYLEGUIDE_CPPLINT_CPPLINT_TEST_HEADER_H_',
cpplint.GetHeaderGuardCPPVariable(file_path))

# (using relative paths)
styleguide_rel_path = os.path.relpath(styleguide_path, this_files_path)
# '..'
cpplint._root = styleguide_rel_path
self.assertEquals('CPPLINT_CPPLINT_TEST_HEADER_H_',
cpplint.GetHeaderGuardCPPVariable(file_path))

styleguide_rel_path = os.path.relpath(styleguide_parent_path,
this_files_path) # '../..'
cpplint._root = styleguide_rel_path
self.assertEquals('STYLEGUIDE_CPPLINT_CPPLINT_TEST_HEADER_H_',
cpplint.GetHeaderGuardCPPVariable(file_path))

cpplint._root = None

def testPathSplitToList(self):
self.assertEquals([''],
cpplint.PathSplitToList(os.path.join('')))

self.assertEquals(['.'],
cpplint.PathSplitToList(os.path.join('.')))

self.assertEquals(['..'],
cpplint.PathSplitToList(os.path.join('..')))

self.assertEquals(['..', 'a', 'b'],
cpplint.PathSplitToList(os.path.join('..', 'a', 'b')))

self.assertEquals(['a', 'b', 'c', 'd'],
cpplint.PathSplitToList(os.path.join('a', 'b', 'c', 'd')))

def testBuildInclude(self):
# Test that include statements have slashes in them.
self.TestLint('#include "foo.h"',
Expand Down

0 comments on commit e7ddd2a

Please sign in to comment.