Run include order check in doc-check
[alexxy/gromacs.git] / docs / doxygen / gmxtree.py
index 1c28e6a3e416fee1ce5209ed18b16cb2bb065e09..67240f391f603074436a3e1c5297ecd2f3a572aa 100644 (file)
@@ -54,6 +54,7 @@ import collections
 import os
 import os.path
 import re
 import os
 import os.path
 import re
+import subprocess
 
 import doxygenxml as xml
 import reporter
 
 import doxygenxml as xml
 import reporter
@@ -76,7 +77,7 @@ class IncludedFile(object):
 
     """Information about an #include directive in a file."""
 
 
     """Information about an #include directive in a file."""
 
-    def __init__(self, including_file, lineno, included_file, included_path, is_relative, is_system):
+    def __init__(self, including_file, lineno, included_file, included_path, is_relative, is_system, line):
         self._including_file = including_file
         self._line_number = lineno
         self._included_file = included_file
         self._including_file = including_file
         self._line_number = lineno
         self._included_file = included_file
@@ -84,6 +85,7 @@ class IncludedFile(object):
         #self._used_include_path = used_include_path
         self._is_relative = is_relative
         self._is_system = is_system
         #self._used_include_path = used_include_path
         self._is_relative = is_relative
         self._is_system = is_system
+        self._line = line
 
     def __str__(self):
         if self._is_system:
 
     def __str__(self):
         if self._is_system:
@@ -109,6 +111,12 @@ class IncludedFile(object):
     def get_line_number(self):
         return self._line_number
 
     def get_line_number(self):
         return self._line_number
 
+    def get_full_line(self):
+        """Return the full source line on which this include appears.
+
+        Trailing newline is included."""
+        return self._line
+
     def get_reporter_location(self):
         return reporter.Location(self._including_file.get_abspath(), self._line_number)
 
     def get_reporter_location(self):
         return reporter.Location(self._including_file.get_abspath(), self._line_number)
 
@@ -154,6 +162,7 @@ class File(object):
         self._include_blocks = []
         self._main_header = None
         self._lines = None
         self._include_blocks = []
         self._main_header = None
         self._lines = None
+        self._filter = None
         directory.add_file(self)
 
     def set_doc_xml(self, rawdoc, sourcetree):
         directory.add_file(self)
 
     def set_doc_xml(self, rawdoc, sourcetree):
@@ -173,12 +182,16 @@ class File(object):
         """Mark the file installed."""
         self._installed = True
 
         """Mark the file installed."""
         self._installed = True
 
+    def set_git_filter_attribute(self, filtername):
+        """Set the git filter attribute associated with the file."""
+        self._filter = filtername
+
     def set_main_header(self, included_file):
         """Set the main header file for a source file."""
         assert self.is_source_file()
         self._main_header = included_file
 
     def set_main_header(self, included_file):
         """Set the main header file for a source file."""
         assert self.is_source_file()
         self._main_header = included_file
 
-    def _process_include(self, lineno, is_system, includedpath, sourcetree):
+    def _process_include(self, lineno, is_system, includedpath, line, sourcetree):
         """Process #include directive during scan()."""
         is_relative = False
         if is_system:
         """Process #include directive during scan()."""
         is_relative = False
         if is_system:
@@ -192,7 +205,7 @@ class File(object):
             else:
                 fileobj = sourcetree.find_include_file(includedpath)
         included_file = IncludedFile(self, lineno, fileobj, includedpath,
             else:
                 fileobj = sourcetree.find_include_file(includedpath)
         included_file = IncludedFile(self, lineno, fileobj, includedpath,
-            is_relative, is_system)
+            is_relative, is_system, line)
         self._includes.append(included_file)
         return included_file
 
         self._includes.append(included_file)
         return included_file
 
@@ -211,7 +224,7 @@ class File(object):
                     is_system = (match.group('quote') == '<')
                     includedpath = match.group('path')
                     included_file = self._process_include(lineno, is_system,
                     is_system = (match.group('quote') == '<')
                     includedpath = match.group('path')
                     included_file = self._process_include(lineno, is_system,
-                            includedpath, sourcetree)
+                            includedpath, line, sourcetree)
                     if current_block is None:
                         current_block = IncludeBlock(included_file)
                         self._include_blocks.append(current_block)
                     if current_block is None:
                         current_block = IncludeBlock(included_file)
                         self._include_blocks.append(current_block)
@@ -237,6 +250,10 @@ class File(object):
     def is_test_file(self):
         return self._dir.is_test_directory()
 
     def is_test_file(self):
         return self._dir.is_test_directory()
 
+    def should_includes_be_sorted(self):
+        """Return whether the include directives in the file should be sorted."""
+        return self._filter in ('includesort', 'uncrustify')
+
     def is_documented(self):
         return self._rawdoc and self._rawdoc.is_documented()
 
     def is_documented(self):
         return self._rawdoc and self._rawdoc.is_documented()
 
@@ -602,6 +619,9 @@ class GromacsTree(object):
     subdirectories.  At this point, only information that is accessible from
     file names and paths only is available.
 
     subdirectories.  At this point, only information that is accessible from
     file names and paths only is available.
 
+    load_git_attributes() can be called to load attribute information from
+    .gitattributes for all the files.
+
     load_installed_file_list() can be called to load the list of installed
     files from the build tree (generated by the find-installed-headers target).
 
     load_installed_file_list() can be called to load the list of installed
     files from the build tree (generated by the find-installed-headers target).
 
@@ -872,6 +892,19 @@ class GromacsTree(object):
             if testpath in self._files:
                 return self._files[testpath]
 
             if testpath in self._files:
                 return self._files[testpath]
 
+    def load_git_attributes(self):
+        """Load git attribute information for files."""
+        args = ['git', 'check-attr', '--stdin', 'filter']
+        git_check_attr = subprocess.Popen(args, stdin=subprocess.PIPE,
+                stdout=subprocess.PIPE, cwd=self._source_root)
+        filelist = '\n'.join(map(File.get_relpath, self._files.itervalues()))
+        filters = git_check_attr.communicate(filelist)[0]
+        for fileinfo in filters.splitlines():
+            path, dummy, value = fileinfo.split(': ')
+            fileobj = self._files.get(path)
+            assert fileobj is not None
+            fileobj.set_git_filter_attribute(value)
+
     def load_installed_file_list(self):
         """Load list of installed files from the build tree."""
         listpath = os.path.join(self._build_root, 'docs', 'doxygen', 'installed-headers.txt')
     def load_installed_file_list(self):
         """Load list of installed files from the build tree."""
         listpath = os.path.join(self._build_root, 'docs', 'doxygen', 'installed-headers.txt')