diff options
Diffstat (limited to 'sphinx/cmd/make_mode.py')
-rw-r--r-- | sphinx/cmd/make_mode.py | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/sphinx/cmd/make_mode.py b/sphinx/cmd/make_mode.py new file mode 100644 index 0000000..8b26d9d --- /dev/null +++ b/sphinx/cmd/make_mode.py @@ -0,0 +1,181 @@ +"""sphinx-build -M command-line handling. + +This replaces the old, platform-dependent and once-generated content +of Makefile / make.bat. + +This is in its own module so that importing it is fast. It should not +import the main Sphinx modules (like sphinx.applications, sphinx.builders). +""" + +from __future__ import annotations + +import os +import subprocess +import sys +from os import path +from typing import TYPE_CHECKING + +import sphinx +from sphinx.cmd.build import build_main +from sphinx.util.console import ( # type: ignore[attr-defined] + blue, + bold, + color_terminal, + nocolor, +) +from sphinx.util.osutil import rmtree + +try: + from contextlib import chdir # type: ignore[attr-defined] +except ImportError: + from sphinx.util.osutil import _chdir as chdir + +if TYPE_CHECKING: + from collections.abc import Sequence + +BUILDERS = [ + ("", "html", "to make standalone HTML files"), + ("", "dirhtml", "to make HTML files named index.html in directories"), + ("", "singlehtml", "to make a single large HTML file"), + ("", "pickle", "to make pickle files"), + ("", "json", "to make JSON files"), + ("", "htmlhelp", "to make HTML files and an HTML help project"), + ("", "qthelp", "to make HTML files and a qthelp project"), + ("", "devhelp", "to make HTML files and a Devhelp project"), + ("", "epub", "to make an epub"), + ("", "latex", "to make LaTeX files, you can set PAPER=a4 or PAPER=letter"), + ("posix", "latexpdf", "to make LaTeX and PDF files (default pdflatex)"), + ("posix", "latexpdfja", "to make LaTeX files and run them through platex/dvipdfmx"), + ("", "text", "to make text files"), + ("", "man", "to make manual pages"), + ("", "texinfo", "to make Texinfo files"), + ("posix", "info", "to make Texinfo files and run them through makeinfo"), + ("", "gettext", "to make PO message catalogs"), + ("", "changes", "to make an overview of all changed/added/deprecated items"), + ("", "xml", "to make Docutils-native XML files"), + ("", "pseudoxml", "to make pseudoxml-XML files for display purposes"), + ("", "linkcheck", "to check all external links for integrity"), + ("", "doctest", "to run all doctests embedded in the documentation " + "(if enabled)"), + ("", "coverage", "to run coverage check of the documentation (if enabled)"), + ("", "clean", "to remove everything in the build directory"), +] + + +class Make: + def __init__(self, srcdir: str, builddir: str, opts: Sequence[str]) -> None: + self.srcdir = srcdir + self.builddir = builddir + self.opts = [*opts] + + def builddir_join(self, *comps: str) -> str: + return path.join(self.builddir, *comps) + + def build_clean(self) -> int: + srcdir = path.abspath(self.srcdir) + builddir = path.abspath(self.builddir) + if not path.exists(self.builddir): + return 0 + elif not path.isdir(self.builddir): + print("Error: %r is not a directory!" % self.builddir) + return 1 + elif srcdir == builddir: + print("Error: %r is same as source directory!" % self.builddir) + return 1 + elif path.commonpath([srcdir, builddir]) == builddir: + print("Error: %r directory contains source directory!" % self.builddir) + return 1 + print("Removing everything under %r..." % self.builddir) + for item in os.listdir(self.builddir): + rmtree(self.builddir_join(item)) + return 0 + + def build_help(self) -> None: + if not color_terminal(): + nocolor() + + print(bold("Sphinx v%s" % sphinx.__display_version__)) + print("Please use `make %s' where %s is one of" % ((blue('target'),) * 2)) + for osname, bname, description in BUILDERS: + if not osname or os.name == osname: + print(f' {blue(bname.ljust(10))} {description}') + + def build_latexpdf(self) -> int: + if self.run_generic_build('latex') > 0: + return 1 + + # Use $MAKE to determine the make command + make_fallback = 'make.bat' if sys.platform == 'win32' else 'make' + makecmd = os.environ.get('MAKE', make_fallback) + if not makecmd.lower().startswith('make'): + raise RuntimeError('Invalid $MAKE command: %r' % makecmd) + try: + with chdir(self.builddir_join('latex')): + return subprocess.call([makecmd, 'all-pdf']) + except OSError: + print('Error: Failed to run: %s' % makecmd) + return 1 + + def build_latexpdfja(self) -> int: + if self.run_generic_build('latex') > 0: + return 1 + + # Use $MAKE to determine the make command + make_fallback = 'make.bat' if sys.platform == 'win32' else 'make' + makecmd = os.environ.get('MAKE', make_fallback) + if not makecmd.lower().startswith('make'): + raise RuntimeError('Invalid $MAKE command: %r' % makecmd) + try: + with chdir(self.builddir_join('latex')): + return subprocess.call([makecmd, 'all-pdf']) + except OSError: + print('Error: Failed to run: %s' % makecmd) + return 1 + + def build_info(self) -> int: + if self.run_generic_build('texinfo') > 0: + return 1 + + # Use $MAKE to determine the make command + makecmd = os.environ.get('MAKE', 'make') + if not makecmd.lower().startswith('make'): + raise RuntimeError('Invalid $MAKE command: %r' % makecmd) + try: + with chdir(self.builddir_join('texinfo')): + return subprocess.call([makecmd, 'info']) + except OSError: + print('Error: Failed to run: %s' % makecmd) + return 1 + + def build_gettext(self) -> int: + dtdir = self.builddir_join('gettext', '.doctrees') + if self.run_generic_build('gettext', doctreedir=dtdir) > 0: + return 1 + return 0 + + def run_generic_build(self, builder: str, doctreedir: str | None = None) -> int: + # compatibility with old Makefile + papersize = os.getenv('PAPER', '') + opts = self.opts + if papersize in ('a4', 'letter'): + opts.extend(['-D', 'latex_elements.papersize=' + papersize + 'paper']) + if doctreedir is None: + doctreedir = self.builddir_join('doctrees') + + args = ['-b', builder, + '-d', doctreedir, + self.srcdir, + self.builddir_join(builder)] + return build_main(args + opts) + + +def run_make_mode(args: Sequence[str]) -> int: + if len(args) < 3: + print('Error: at least 3 arguments (builder, source ' + 'dir, build dir) are required.', file=sys.stderr) + return 1 + make = Make(args[1], args[2], args[3:]) + run_method = 'build_' + args[0] + if hasattr(make, run_method): + return getattr(make, run_method)() + return make.run_generic_build(args[0]) |