Run include order check in doc-check
[alexxy/gromacs.git] / docs / doxygen / includesorter.py
index 23c2ecf0c6491985a8c902e1b0f88fb4b4667790..635bf53256b082a538db3e0c6432f6c38ffd21a0 100755 (executable)
@@ -40,8 +40,10 @@ It allows (in most cases) automatically sorting includes and formatting
 the paths to use either relative paths or paths relative to src/.
 It groups includes in groups of related headers, sorts the headers
 alphabetically within each block, and inserts empty lines in between.
 the paths to use either relative paths or paths relative to src/.
 It groups includes in groups of related headers, sorts the headers
 alphabetically within each block, and inserts empty lines in between.
-The script requires an up-to-date list of installed headers and Doxygen XML
-documentation to be present in the build tree.
+It can be run as a standalone script, in which case it requires an up-to-date
+list of installed headers and Doxygen XML documentation to be present in the
+build tree.  It can also be imported as a module to be embedded in other
+scripts.  In the latter case, the IncludeSorter provides the main interface.
 
 The sorting assumes some conventions (e.g., that system headers are included
 with angle brackets instead of quotes).  Generally, these conventions are
 
 The sorting assumes some conventions (e.g., that system headers are included
 with angle brackets instead of quotes).  Generally, these conventions are
@@ -108,7 +110,7 @@ class GroupedSorter(object):
             'regex', 'set', 'sstream', 'stdexcept', 'streambuf', 'string', 'strstream',
             'typeinfo', 'vector', 'utility']
 
             'regex', 'set', 'sstream', 'stdexcept', 'streambuf', 'string', 'strstream',
             'typeinfo', 'vector', 'utility']
 
-    def __init__(self, style, absolute):
+    def __init__(self, style='pub-priv', absolute=False):
         """Initialize a sorted with the given style."""
         if style == 'single-group':
             self._local_group = 'none'
         """Initialize a sorted with the given style."""
         if style == 'single-group':
             self._local_group = 'none'
@@ -210,7 +212,7 @@ class GroupedSorter(object):
             path = self._get_path(included_file, group, including_file)
         return (group, os.path.split(path), include)
 
             path = self._get_path(included_file, group, including_file)
         return (group, os.path.split(path), include)
 
-    def format_include(self, obj, prev, lines):
+    def format_include(self, obj, prev):
         """Format an #include directive after sorting."""
         result = []
         if prev:
         """Format an #include directive after sorting."""
         result = []
         if prev:
@@ -221,7 +223,7 @@ class GroupedSorter(object):
                 # Skip duplicates
                 return result
         include = obj[2]
                 # Skip duplicates
                 return result
         include = obj[2]
-        line = lines[include.get_line_number()-1]
+        line = include.get_full_line()
         include_re = r'^(?P<head>\s*#\s*include\s+)["<][^">]*[">](?P<tail>.*)$'
         match = re.match(include_re, line)
         assert match
         include_re = r'^(?P<head>\s*#\s*include\s+)["<][^">]*[">](?P<tail>.*)$'
         match = re.match(include_re, line)
         assert match
@@ -241,8 +243,10 @@ class IncludeSorter(object):
     (see GroupedSorter) to keep things separated.
     """
 
     (see GroupedSorter) to keep things separated.
     """
 
-    def __init__(self, sortmethod, quiet):
+    def __init__(self, sortmethod=None, quiet=True):
         """Initialize the include sorter with the given sorter and options."""
         """Initialize the include sorter with the given sorter and options."""
+        if not sortmethod:
+            sortmethod = GroupedSorter()
         self._sortmethod = sortmethod
         self._quiet = quiet
         self._changed = False
         self._sortmethod = sortmethod
         self._quiet = quiet
         self._changed = False
@@ -259,7 +263,7 @@ class IncludeSorter(object):
         prev = None
         current_line_number = block.get_first_line()-1
         for include in includes:
         prev = None
         current_line_number = block.get_first_line()-1
         for include in includes:
-            newlines = self._sortmethod.format_include(include, prev, lines)
+            newlines = self._sortmethod.format_include(include, prev)
             result.extend(newlines)
             if not self._changed:
                 for offset, newline in enumerate(newlines):
             result.extend(newlines)
             if not self._changed:
                 for offset, newline in enumerate(newlines):
@@ -292,6 +296,15 @@ class IncludeSorter(object):
             with open(fileobj.get_abspath(), 'w') as fp:
                 fp.write(''.join(newlines))
 
             with open(fileobj.get_abspath(), 'w') as fp:
                 fp.write(''.join(newlines))
 
+    def check_sorted(self, fileobj):
+        """Check that includes within a file are sorted."""
+        # TODO: Make the checking work without full contents of the file
+        lines = fileobj.get_contents()
+        self._changed = False
+        for block in fileobj.get_include_blocks():
+            self._sort_include_block(block, lines)
+        return not self._changed
+
 def main():
     """Run the include sorter script."""
     import os
 def main():
     """Run the include sorter script."""
     import os