~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/Documentation/sphinx/maintainers_include.py

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 #!/usr/bin/env python
  2 # SPDX-License-Identifier: GPL-2.0
  3 # -*- coding: utf-8; mode: python -*-
  4 # pylint: disable=R0903, C0330, R0914, R0912, E0401
  5 
  6 u"""
  7     maintainers-include
  8     ~~~~~~~~~~~~~~~~~~~
  9 
 10     Implementation of the ``maintainers-include`` reST-directive.
 11 
 12     :copyright:  Copyright (C) 2019  Kees Cook <keescook@chromium.org>
 13     :license:    GPL Version 2, June 1991 see linux/COPYING for details.
 14 
 15     The ``maintainers-include`` reST-directive performs extensive parsing
 16     specific to the Linux kernel's standard "MAINTAINERS" file, in an
 17     effort to avoid needing to heavily mark up the original plain text.
 18 """
 19 
 20 import sys
 21 import re
 22 import os.path
 23 
 24 from docutils import statemachine
 25 from docutils.utils.error_reporting import ErrorString
 26 from docutils.parsers.rst import Directive
 27 from docutils.parsers.rst.directives.misc import Include
 28 
 29 __version__  = '1.0'
 30 
 31 def setup(app):
 32     app.add_directive("maintainers-include", MaintainersInclude)
 33     return dict(
 34         version = __version__,
 35         parallel_read_safe = True,
 36         parallel_write_safe = True
 37     )
 38 
 39 class MaintainersInclude(Include):
 40     u"""MaintainersInclude (``maintainers-include``) directive"""
 41     required_arguments = 0
 42 
 43     def parse_maintainers(self, path):
 44         """Parse all the MAINTAINERS lines into ReST for human-readability"""
 45 
 46         result = list()
 47         result.append(".. _maintainers:")
 48         result.append("")
 49 
 50         # Poor man's state machine.
 51         descriptions = False
 52         maintainers = False
 53         subsystems = False
 54 
 55         # Field letter to field name mapping.
 56         field_letter = None
 57         fields = dict()
 58 
 59         prev = None
 60         field_prev = ""
 61         field_content = ""
 62 
 63         for line in open(path):
 64             # Have we reached the end of the preformatted Descriptions text?
 65             if descriptions and line.startswith('Maintainers'):
 66                 descriptions = False
 67                 # Ensure a blank line following the last "|"-prefixed line.
 68                 result.append("")
 69 
 70             # Start subsystem processing? This is to skip processing the text
 71             # between the Maintainers heading and the first subsystem name.
 72             if maintainers and not subsystems:
 73                 if re.search('^[A-Z0-9]', line):
 74                     subsystems = True
 75 
 76             # Drop needless input whitespace.
 77             line = line.rstrip()
 78 
 79             # Linkify all non-wildcard refs to ReST files in Documentation/.
 80             pat = r'(Documentation/([^\s\?\*]*)\.rst)'
 81             m = re.search(pat, line)
 82             if m:
 83                 # maintainers.rst is in a subdirectory, so include "../".
 84                 line = re.sub(pat, ':doc:`%s <../%s>`' % (m.group(2), m.group(2)), line)
 85 
 86             # Check state machine for output rendering behavior.
 87             output = None
 88             if descriptions:
 89                 # Escape the escapes in preformatted text.
 90                 output = "| %s" % (line.replace("\\", "\\\\"))
 91                 # Look for and record field letter to field name mappings:
 92                 #   R: Designated *reviewer*: FullName <address@domain>
 93                 m = re.search(r"\s(\S):\s", line)
 94                 if m:
 95                     field_letter = m.group(1)
 96                 if field_letter and not field_letter in fields:
 97                     m = re.search(r"\*([^\*]+)\*", line)
 98                     if m:
 99                         fields[field_letter] = m.group(1)
100             elif subsystems:
101                 # Skip empty lines: subsystem parser adds them as needed.
102                 if len(line) == 0:
103                     continue
104                 # Subsystem fields are batched into "field_content"
105                 if line[1] != ':':
106                     # Render a subsystem entry as:
107                     #   SUBSYSTEM NAME
108                     #   ~~~~~~~~~~~~~~
109 
110                     # Flush pending field content.
111                     output = field_content + "\n\n"
112                     field_content = ""
113 
114                     # Collapse whitespace in subsystem name.
115                     heading = re.sub(r"\s+", " ", line)
116                     output = output + "%s\n%s" % (heading, "~" * len(heading))
117                     field_prev = ""
118                 else:
119                     # Render a subsystem field as:
120                     #   :Field: entry
121                     #           entry...
122                     field, details = line.split(':', 1)
123                     details = details.strip()
124 
125                     # Mark paths (and regexes) as literal text for improved
126                     # readability and to escape any escapes.
127                     if field in ['F', 'N', 'X', 'K']:
128                         # But only if not already marked :)
129                         if not ':doc:' in details:
130                             details = '``%s``' % (details)
131 
132                     # Comma separate email field continuations.
133                     if field == field_prev and field_prev in ['M', 'R', 'L']:
134                         field_content = field_content + ","
135 
136                     # Do not repeat field names, so that field entries
137                     # will be collapsed together.
138                     if field != field_prev:
139                         output = field_content + "\n"
140                         field_content = ":%s:" % (fields.get(field, field))
141                     field_content = field_content + "\n\t%s" % (details)
142                     field_prev = field
143             else:
144                 output = line
145 
146             # Re-split on any added newlines in any above parsing.
147             if output != None:
148                 for separated in output.split('\n'):
149                     result.append(separated)
150 
151             # Update the state machine when we find heading separators.
152             if line.startswith('----------'):
153                 if prev.startswith('Descriptions'):
154                     descriptions = True
155                 if prev.startswith('Maintainers'):
156                     maintainers = True
157 
158             # Retain previous line for state machine transitions.
159             prev = line
160 
161         # Flush pending field contents.
162         if field_content != "":
163             for separated in field_content.split('\n'):
164                 result.append(separated)
165 
166         output = "\n".join(result)
167         # For debugging the pre-rendered results...
168         #print(output, file=open("/tmp/MAINTAINERS.rst", "w"))
169 
170         self.state_machine.insert_input(
171           statemachine.string2lines(output), path)
172 
173     def run(self):
174         """Include the MAINTAINERS file as part of this reST file."""
175         if not self.state.document.settings.file_insertion_enabled:
176             raise self.warning('"%s" directive disabled.' % self.name)
177 
178         # Walk up source path directories to find Documentation/../
179         path = self.state_machine.document.attributes['source']
180         path = os.path.realpath(path)
181         tail = path
182         while tail != "Documentation" and tail != "":
183             (path, tail) = os.path.split(path)
184 
185         # Append "MAINTAINERS"
186         path = os.path.join(path, "MAINTAINERS")
187 
188         try:
189             self.state.document.settings.record_dependencies.add(path)
190             lines = self.parse_maintainers(path)
191         except IOError as error:
192             raise self.severe('Problems with "%s" directive path:\n%s.' %
193                       (self.name, ErrorString(error)))
194 
195         return []

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php