diff --git a/cpplint/cpplint.py b/cpplint/cpplint.py index 52cb7d0ca..7c624f2ad 100755 --- a/cpplint/cpplint.py +++ b/cpplint/cpplint.py @@ -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. @@ -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() + '_' diff --git a/cpplint/cpplint_unittest.py b/cpplint/cpplint_unittest.py index 4931523cd..30f640e23 100755 --- a/cpplint/cpplint_unittest.py +++ b/cpplint/cpplint_unittest.py @@ -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)) @@ -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"',