~ [ 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 ] ~

Diff markup

Differences between /Documentation/sphinx/maintainers_include.py (Version linux-6.12-rc7) and /Documentation/sphinx/maintainers_include.py (Version linux-5.9.16)


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