docs: maintainers_include: fix support for O=dir

os.path.relpath() will do the wrong thing with O=dir, as the build
system uses "cd <dir>" internally.

Solve it by using app.srcdir, which, on normal cases, point to
Documentation/, or, when SPHINXDIRS=process, it will be set with
Documentation/process.

While here, remove a dead code while writing maintainer profiles,
as now all entries should have both profile and entry.

Reported-by: Randy Dunlap <rdunlap@infradead.org>
Closes: https://lore.kernel.org/linux-doc/88335220-3527-4b1f-9500-417f7ebb7a02@infradead.org/T/#m6854cbd8d30e2c5d3e8c4173bae1c3d6922ff970
Reviewed-by: Randy Dunlap <rdunlap@infradead.org>
Tested-by: Randy Dunlap <rdunlap@infradead.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Signed-off-by: Jonathan Corbet <corbet@lwn.net>
Message-ID: <193792d73d08d9f8b9faa8b3df8a1a7439344a28.1777295258.git.mchehab+huawei@kernel.org>
This commit is contained in:
Mauro Carvalho Chehab 2026-04-27 16:22:27 +02:00 committed by Jonathan Corbet
parent 237abdfaa6
commit 6aaf2e91a1

View File

@ -27,15 +27,24 @@ from docutils import statemachine
from docutils.parsers.rst import Directive
from docutils.parsers.rst.directives.misc import Include
#
# Base URL for intersphinx-like links to maintainer profiles
#
KERNELDOC_URL = "https://docs.kernel.org/"
def ErrorString(exc): # Shamelessly stolen from docutils
return f'{exc.__class__.__name}: {exc}'
__version__ = '1.0'
app_dir = "."
class MaintainersParser:
"""Parse MAINTAINERS file(s) content"""
def __init__(self, base_path, path):
def __init__(self, path):
global app_dir
self.profile_toc = set()
self.profile_entries = {}
@ -57,6 +66,9 @@ class MaintainersParser:
field_content = ""
subsystem_name = None
base_dir, doc_dir, sphinx_dir = app_dir.partition("Documentation")
print("BASE DIR", base_dir)
for line in open(path):
# Have we reached the end of the preformatted Descriptions text?
if descriptions and line.startswith('Maintainers'):
@ -76,9 +88,25 @@ class MaintainersParser:
#
# Handle profile entries - either as files or as https refs
#
match = re.match(r"P:\s*(Documentation/\S+)\.rst", line)
match = re.match(rf"P:\s*({doc_dir})(/\S+)\.rst", line)
if match:
entry = os.path.relpath(match.group(1), base_path)
name = "".join(match.groups())
entry = os.path.relpath(base_dir + name, app_dir)
full_name = os.path.join(base_dir, name)
path = os.path.relpath(full_name, app_dir)
#
# When SPHINXDIRS is used, it will try to reference files
# outside srctree, causing warnings. To avoid that, point
# to the latest official documentation
#
if path.startswith("../"):
entry = KERNELDOC_URL + match.group(2) + ".html"
else:
entry = "/" + entry
print(f"{name}: entry: {entry} FULL: {full_name} path: {path}")
if "*" in entry:
for e in glob(entry):
self.profile_toc.add(e)
@ -189,10 +217,10 @@ class MaintainersInclude(Include):
"""MaintainersInclude (``maintainers-include``) directive"""
required_arguments = 0
def emit(self, base_path, path):
def emit(self, path):
"""Parse all the MAINTAINERS lines into ReST for human-readability"""
output = MaintainersParser(base_path, path).output
output = MaintainersParser(path).output
# For debugging the pre-rendered results...
#print(output, file=open("/tmp/MAINTAINERS.rst", "w"))
@ -213,11 +241,10 @@ class MaintainersInclude(Include):
# Append "MAINTAINERS"
path = os.path.join(path, "MAINTAINERS")
base_path = os.path.dirname(self.state.document.document.current_source)
try:
self.state.document.settings.record_dependencies.add(path)
lines = self.emit(base_path, path)
lines = self.emit(path)
except IOError as error:
raise self.severe('Problems with "%s" directive path:\n%s.' %
(self.name, ErrorString(error)))
@ -227,27 +254,20 @@ class MaintainersInclude(Include):
class MaintainersProfile(Include):
required_arguments = 0
def emit(self, base_path, path):
def emit(self, path):
"""Parse all the MAINTAINERS lines looking for profile entries"""
maint = MaintainersParser(base_path, path)
maint = MaintainersParser(path)
#
# Produce a list with all maintainer profiles, sorted by subsystem name
#
output = ""
for profile, entry in maint.profile_entries.items():
for profile, entry in sorted(maint.profile_entries.items()):
if entry.startswith("http"):
if profile:
output += f"- `{profile} <{entry}>`_\n"
else:
output += f"- `<{entry}>_`\n"
output += f"- `{profile} <{entry}>`_\n"
else:
if profile:
output += f"- :doc:`{profile} <{entry}>`\n"
else:
output += f"- :doc:`<{entry}>`\n"
output += f"- :doc:`{profile} <{entry}>`\n"
#
# Create a hidden TOC table with all profiles. That allows adding
@ -261,6 +281,8 @@ class MaintainersProfile(Include):
output += "\n"
print(output)
self.state_machine.insert_input(statemachine.string2lines(output), path)
def run(self):
@ -277,11 +299,10 @@ class MaintainersProfile(Include):
# Append "MAINTAINERS"
path = os.path.join(path, "MAINTAINERS")
base_path = os.path.dirname(self.state.document.document.current_source)
try:
self.state.document.settings.record_dependencies.add(path)
lines = self.emit(base_path, path)
lines = self.emit(path)
except IOError as error:
raise self.severe('Problems with "%s" directive path:\n%s.' %
(self.name, ErrorString(error)))
@ -289,6 +310,14 @@ class MaintainersProfile(Include):
return []
def setup(app):
global app_dir
#
# NOTE: we're using os.fspath() here because of a Sphinx warning:
# RemovedInSphinx90Warning: Sphinx 9 will drop support for representing paths as strings. Use "pathlib.Path" or "os.fspath" instead.
#
app_dir = os.fspath(app.srcdir)
app.add_directive("maintainers-include", MaintainersInclude)
app.add_directive("maintainers-profile-toc", MaintainersProfile)
return dict(