|
4 | 4 |
|
5 | 5 | import codecs |
6 | 6 | import pickle |
| 7 | +import re |
7 | 8 | import time |
8 | 9 | from os import path |
9 | 10 | from typing import TYPE_CHECKING, Any, Literal, final |
|
21 | 22 | from sphinx.util.display import progress_message, status_iterator |
22 | 23 | from sphinx.util.docutils import sphinx_domains |
23 | 24 | from sphinx.util.i18n import CatalogInfo, CatalogRepository, docname_to_domain |
24 | | -from sphinx.util.osutil import SEP, ensuredir, relative_uri, relpath |
| 25 | +from sphinx.util.osutil import SEP, canon_path, ensuredir, relative_uri, relpath |
25 | 26 | from sphinx.util.parallel import ParallelTasks, SerialTasks, make_chunks, parallel_available |
26 | 27 |
|
27 | 28 | # side effect: registers roles and directives |
@@ -423,9 +424,40 @@ def read(self) -> list[str]: |
423 | 424 | else: |
424 | 425 | self._read_serial(docnames) |
425 | 426 |
|
426 | | - if self.config.root_doc not in self.env.all_docs: |
427 | | - raise SphinxError('root file %s not found' % |
428 | | - self.env.doc2path(self.config.root_doc)) |
| 427 | + if self.config.master_doc not in self.env.all_docs: |
| 428 | + from sphinx.project import EXCLUDE_PATHS |
| 429 | + from sphinx.util.matching import _translate_pattern |
| 430 | + |
| 431 | + master_doc_path = self.env.doc2path(self.config.master_doc) |
| 432 | + master_doc_canon = canon_path(master_doc_path) |
| 433 | + for pat in EXCLUDE_PATHS: |
| 434 | + if not re.match(_translate_pattern(pat), master_doc_canon): |
| 435 | + continue |
| 436 | + msg = __('Sphinx is unable to load the master document (%s) ' |
| 437 | + 'because it matches a built-in exclude pattern %r. ' |
| 438 | + 'Please move your master document to a different location.') |
| 439 | + raise SphinxError(msg % (master_doc_path, pat)) |
| 440 | + for pat in self.config.exclude_patterns: |
| 441 | + if not re.match(_translate_pattern(pat), master_doc_canon): |
| 442 | + continue |
| 443 | + msg = __('Sphinx is unable to load the master document (%s) ' |
| 444 | + 'because it matches an exclude pattern specified ' |
| 445 | + 'in conf.py, %r. ' |
| 446 | + 'Please remove this pattern from conf.py.') |
| 447 | + raise SphinxError(msg % (master_doc_path, pat)) |
| 448 | + if set(self.config.include_patterns) != {'**'} and not any( |
| 449 | + re.match(_translate_pattern(pat), master_doc_canon) |
| 450 | + for pat in self.config.include_patterns |
| 451 | + ): |
| 452 | + msg = __('Sphinx is unable to load the master document (%s) ' |
| 453 | + 'because it is not included in the custom include_patterns = %r. ' |
| 454 | + 'Ensure that a pattern in include_patterns matches the ' |
| 455 | + 'master document.') |
| 456 | + raise SphinxError(msg % (master_doc_path, self.config.include_patterns)) |
| 457 | + msg = __('Sphinx is unable to load the master document (%s). ' |
| 458 | + 'The master document must be within the source directory ' |
| 459 | + 'or a subdirectory of it.') |
| 460 | + raise SphinxError(msg % master_doc_path) |
429 | 461 |
|
430 | 462 | for retval in self.events.emit('env-updated', self.env): |
431 | 463 | if retval is not None: |
|
0 commit comments