Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

doc-rst: Programmatically render MAINTAINERS into ReST

In order to have the MAINTAINERS file visible in the rendered ReST
output, this makes some small changes to the existing MAINTAINERS file
to allow for better machine processing, and adds a new Sphinx directive
"maintainers-include" to perform the rendering.

Features include:
- Per-subsystem reference links: subsystem maintainer entries can be
trivially linked to both internally and external. For example:
https://www.kernel.org/doc/html/latest/process/maintainers.html#secure-computing

- Internally referenced .rst files are linked so they can be followed
when browsing the resulting rendering. This allows, for example, the
future addition of maintainer profiles to be automatically linked.

- Field name expansion: instead of the short fields (e.g. "M", "F",
"K"), use the indicated inline "full names" for the fields (which are
marked with "*"s in MAINTAINERS) so that a rendered subsystem entry
is more human readable. Email lists are additionally comma-separated.
For example:

SECURE COMPUTING
Mail: Kees Cook <keescook@chromium.org>
Reviewer: Andy Lutomirski <luto@amacapital.net>,
Will Drewry <wad@chromium.org>
SCM: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git seccomp
Status: Supported
Files: kernel/seccomp.c include/uapi/linux/seccomp.h
include/linux/seccomp.h tools/testing/selftests/seccomp/*
tools/testing/selftests/kselftest_harness.h
userspace-api/seccomp_filter
Content regex: \bsecure_computing \bTIF_SECCOMP\b

Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Jonathan Corbet <corbet@lwn.net>

authored by

Kees Cook and committed by
Jonathan Corbet
aa204855 1b1438b5

+233 -31
+2 -1
Documentation/conf.py
··· 37 37 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 38 38 # ones. 39 39 extensions = ['kerneldoc', 'rstFlatTable', 'kernel_include', 'cdomain', 40 - 'kfigure', 'sphinx.ext.ifconfig', 'automarkup'] 40 + 'kfigure', 'sphinx.ext.ifconfig', 'automarkup', 41 + 'maintainers_include'] 41 42 42 43 # The name of the math extension changed on Sphinx 1.4 43 44 if (major == 1 and minor > 3) or (major > 1):
+1
Documentation/process/index.rst
··· 46 46 kernel-docs 47 47 deprecated 48 48 embargoed-hardware-issues 49 + maintainers 49 50 50 51 These are some overall technical guides that have been put here for now for 51 52 lack of a better place.
+1
Documentation/process/maintainers.rst
··· 1 + .. maintainers-include::
+197
Documentation/sphinx/maintainers_include.py
··· 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 + if sys.version_info.major == 2: 65 + line = unicode(line, 'utf-8') 66 + # Have we reached the end of the preformatted Descriptions text? 67 + if descriptions and line.startswith('Maintainers'): 68 + descriptions = False 69 + # Ensure a blank line following the last "|"-prefixed line. 70 + result.append("") 71 + 72 + # Start subsystem processing? This is to skip processing the text 73 + # between the Maintainers heading and the first subsystem name. 74 + if maintainers and not subsystems: 75 + if re.search('^[A-Z0-9]', line): 76 + subsystems = True 77 + 78 + # Drop needless input whitespace. 79 + line = line.rstrip() 80 + 81 + # Linkify all non-wildcard refs to ReST files in Documentation/. 82 + pat = '(Documentation/([^\s\?\*]*)\.rst)' 83 + m = re.search(pat, line) 84 + if m: 85 + # maintainers.rst is in a subdirectory, so include "../". 86 + line = re.sub(pat, ':doc:`%s <../%s>`' % (m.group(2), m.group(2)), line) 87 + 88 + # Check state machine for output rendering behavior. 89 + output = None 90 + if descriptions: 91 + # Escape the escapes in preformatted text. 92 + output = "| %s" % (line.replace("\\", "\\\\")) 93 + # Look for and record field letter to field name mappings: 94 + # R: Designated *reviewer*: FullName <address@domain> 95 + m = re.search("\s(\S):\s", line) 96 + if m: 97 + field_letter = m.group(1) 98 + if field_letter and not field_letter in fields: 99 + m = re.search("\*([^\*]+)\*", line) 100 + if m: 101 + fields[field_letter] = m.group(1) 102 + elif subsystems: 103 + # Skip empty lines: subsystem parser adds them as needed. 104 + if len(line) == 0: 105 + continue 106 + # Subsystem fields are batched into "field_content" 107 + if line[1] != ':': 108 + # Render a subsystem entry as: 109 + # SUBSYSTEM NAME 110 + # ~~~~~~~~~~~~~~ 111 + 112 + # Flush pending field content. 113 + output = field_content + "\n\n" 114 + field_content = "" 115 + 116 + # Collapse whitespace in subsystem name. 117 + heading = re.sub("\s+", " ", line) 118 + output = output + "%s\n%s" % (heading, "~" * len(heading)) 119 + field_prev = "" 120 + else: 121 + # Render a subsystem field as: 122 + # :Field: entry 123 + # entry... 124 + field, details = line.split(':', 1) 125 + details = details.strip() 126 + 127 + # Mark paths (and regexes) as literal text for improved 128 + # readability and to escape any escapes. 129 + if field in ['F', 'N', 'X', 'K']: 130 + # But only if not already marked :) 131 + if not ':doc:' in details: 132 + details = '``%s``' % (details) 133 + 134 + # Comma separate email field continuations. 135 + if field == field_prev and field_prev in ['M', 'R', 'L']: 136 + field_content = field_content + "," 137 + 138 + # Do not repeat field names, so that field entries 139 + # will be collapsed together. 140 + if field != field_prev: 141 + output = field_content + "\n" 142 + field_content = ":%s:" % (fields.get(field, field)) 143 + field_content = field_content + "\n\t%s" % (details) 144 + field_prev = field 145 + else: 146 + output = line 147 + 148 + # Re-split on any added newlines in any above parsing. 149 + if output != None: 150 + for separated in output.split('\n'): 151 + result.append(separated) 152 + 153 + # Update the state machine when we find heading separators. 154 + if line.startswith('----------'): 155 + if prev.startswith('Descriptions'): 156 + descriptions = True 157 + if prev.startswith('Maintainers'): 158 + maintainers = True 159 + 160 + # Retain previous line for state machine transitions. 161 + prev = line 162 + 163 + # Flush pending field contents. 164 + if field_content != "": 165 + for separated in field_content.split('\n'): 166 + result.append(separated) 167 + 168 + output = "\n".join(result) 169 + # For debugging the pre-rendered results... 170 + #print(output, file=open("/tmp/MAINTAINERS.rst", "w")) 171 + 172 + self.state_machine.insert_input( 173 + statemachine.string2lines(output), path) 174 + 175 + def run(self): 176 + """Include the MAINTAINERS file as part of this reST file.""" 177 + if not self.state.document.settings.file_insertion_enabled: 178 + raise self.warning('"%s" directive disabled.' % self.name) 179 + 180 + # Walk up source path directories to find Documentation/../ 181 + path = self.state_machine.document.attributes['source'] 182 + path = os.path.realpath(path) 183 + tail = path 184 + while tail != "Documentation" and tail != "": 185 + (path, tail) = os.path.split(path) 186 + 187 + # Append "MAINTAINERS" 188 + path = os.path.join(path, "MAINTAINERS") 189 + 190 + try: 191 + self.state.document.settings.record_dependencies.add(path) 192 + lines = self.parse_maintainers(path) 193 + except IOError as error: 194 + raise self.severe('Problems with "%s" directive path:\n%s.' % 195 + (self.name, ErrorString(error))) 196 + 197 + return []
+32 -30
MAINTAINERS
··· 1 - 2 - 3 - List of maintainers and how to submit kernel changes 1 + List of maintainers and how to submit kernel changes 2 + ==================================================== 4 3 5 4 Please try to follow the guidelines below. This will make things 6 5 easier on the maintainers. Not all of these guidelines matter for every 7 6 trivial patch so apply some common sense. 8 7 9 - 1. Always _test_ your changes, however small, on at least 4 or 8 + Tips for patch submitters 9 + ------------------------- 10 + 11 + 1. Always *test* your changes, however small, on at least 4 or 10 12 5 people, preferably many more. 11 13 12 14 2. Try to release a few ALPHA test versions to the net. Announce ··· 27 25 testing and await feedback. 28 26 29 27 5. Make a patch available to the relevant maintainer in the list. Use 30 - 'diff -u' to make the patch easy to merge. Be prepared to get your 28 + ``diff -u`` to make the patch easy to merge. Be prepared to get your 31 29 changes sent back with seemingly silly requests about formatting 32 30 and variable names. These aren't as silly as they seem. One 33 31 job the maintainers (and especially Linus) do is to keep things ··· 40 38 See Documentation/process/coding-style.rst for guidance here. 41 39 42 40 PLEASE CC: the maintainers and mailing lists that are generated 43 - by scripts/get_maintainer.pl. The results returned by the 41 + by ``scripts/get_maintainer.pl.`` The results returned by the 44 42 script will be best if you have git installed and are making 45 43 your changes in a branch derived from Linus' latest git tree. 46 44 See Documentation/process/submitting-patches.rst for details. ··· 72 70 not represent an immediate threat and are better handled publicly, 73 71 and ideally, should come with a patch proposal. Please do not send 74 72 automated reports to this list either. Such bugs will be handled 75 - better and faster in the usual public places. 73 + better and faster in the usual public places. See 74 + Documentation/admin-guide/security-bugs.rst for details. 76 75 77 76 8. Happy hacking. 78 77 79 - Descriptions of section entries: 78 + Descriptions of section entries 79 + ------------------------------- 80 80 81 - P: Person (obsolete) 82 - M: Mail patches to: FullName <address@domain> 83 - R: Designated reviewer: FullName <address@domain> 81 + M: *Mail* patches to: FullName <address@domain> 82 + R: Designated *Reviewer*: FullName <address@domain> 84 83 These reviewers should be CCed on patches. 85 - L: Mailing list that is relevant to this area 86 - W: Web-page with status/info 87 - B: URI for where to file bugs. A web-page with detailed bug 84 + L: *Mailing list* that is relevant to this area 85 + W: *Web-page* with status/info 86 + B: URI for where to file *bugs*. A web-page with detailed bug 88 87 filing info, a direct bug tracker link, or a mailto: URI. 89 - C: URI for chat protocol, server and channel where developers 88 + C: URI for *chat* protocol, server and channel where developers 90 89 usually hang out, for example irc://server/channel. 91 - Q: Patchwork web based patch tracking system site 92 - T: SCM tree type and location. 90 + Q: *Patchwork* web based patch tracking system site 91 + T: *SCM* tree type and location. 93 92 Type is one of: git, hg, quilt, stgit, topgit 94 - S: Status, one of the following: 93 + S: *Status*, one of the following: 95 94 Supported: Someone is actually paid to look after this. 96 95 Maintained: Someone actually looks after it. 97 96 Odd Fixes: It has a maintainer but they don't have time to do ··· 102 99 Obsolete: Old code. Something tagged obsolete generally means 103 100 it has been replaced by a better system and you 104 101 should be using that. 105 - F: Files and directories with wildcard patterns. 102 + F: *Files* and directories wildcard patterns. 106 103 A trailing slash includes all files and subdirectory files. 107 104 F: drivers/net/ all files in and below drivers/net 108 105 F: drivers/net/* all files in drivers/net, but not below 109 106 F: */net/* all files in "any top level directory"/net 110 107 One pattern per line. Multiple F: lines acceptable. 111 - N: Files and directories with regex patterns. 108 + N: Files and directories *Regex* patterns. 112 109 N: [^a-z]tegra all files whose path contains the word tegra 113 110 One pattern per line. Multiple N: lines acceptable. 114 111 scripts/get_maintainer.pl has different behavior for files that ··· 116 113 get_maintainer will not look at git log history when an F: pattern 117 114 match occurs. When an N: match occurs, git log history is used 118 115 to also notify the people that have git commit signatures. 119 - X: Files and directories that are NOT maintained, same rules as F: 120 - Files exclusions are tested before file matches. 116 + X: *Excluded* files and directories that are NOT maintained, same 117 + rules as F:. Files exclusions are tested before file matches. 121 118 Can be useful for excluding a specific subdirectory, for instance: 122 119 F: net/ 123 120 X: net/ipv6/ 124 121 matches all files in and below net excluding net/ipv6/ 125 - K: Keyword perl extended regex pattern to match content in a 126 - patch or file. For instance: 122 + K: *Content regex* (perl extended) pattern match in a patch or file. 123 + For instance: 127 124 K: of_get_profile 128 125 matches patches or files that contain "of_get_profile" 129 126 K: \b(printk|pr_(info|err))\b ··· 131 128 printk, pr_info or pr_err 132 129 One regex pattern per line. Multiple K: lines acceptable. 133 130 134 - Note: For the hard of thinking, this list is meant to remain in alphabetical 135 - order. If you could add yourselves to it in alphabetical order that would be 136 - so much easier [Ed] 131 + Maintainers List 132 + ---------------- 137 133 138 - Maintainers List (try to look for most precise areas first) 139 - 140 - ----------------------------------- 134 + .. note:: When reading this list, please look for the most precise areas 135 + first. When adding to this list, please keep the entries in 136 + alphabetical order. 141 137 142 138 3C59X NETWORK DRIVER 143 139 M: Steffen Klassert <klassert@kernel.org>