From 1c444e255066a26481428a383a4e614f4fd0bbf4 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Tue, 12 Mar 2019 18:16:26 +0100 Subject: [PATCH] Use latexmk command to build PDF files New versions of Sphinx use `latexmk` to build the PDF files. This command uses a file called `latexmkrc` (or `latexmkjarc` for Japanese) which contains all the proper commands that needs to be ran depending on different Sphinx configurations. `latexmk` will take care by itself on the amount of phases that need to be ran without us worrying about it. Currently, this is not considering LATEXMKOPTS and XINDYOPTS environment variables configured by Sphinx. This feature is implemented under a Feature flag so we can test it easily without breaking other working projects. References: - https://github.com/rtfd/readthedocs.org/issues/1556 - https://github.com/rtfd/readthedocs.org/issues/4454 - https://github.com/rtfd/readthedocs.org/pull/5405 - https://github.com/TECS-WG/tecs-docs/issues/7 - https://github.com/sphinx-doc/sphinx/blob/master/sphinx/texinputs/Makefile_t - https://www.sphinx-doc.org/en/master/usage/builders/index.html#sphinx.builders.latex.LaTeXBuilder --- readthedocs/doc_builder/backends/sphinx.py | 53 ++++++++++++++++++++++ readthedocs/projects/models.py | 2 + 2 files changed, 55 insertions(+) diff --git a/readthedocs/doc_builder/backends/sphinx.py b/readthedocs/doc_builder/backends/sphinx.py index 99592139433..c0257ef95db 100644 --- a/readthedocs/doc_builder/backends/sphinx.py +++ b/readthedocs/doc_builder/backends/sphinx.py @@ -6,12 +6,14 @@ .. _Sphinx: http://www.sphinx-doc.org/ """ import codecs +import itertools import logging import os import shutil import sys import zipfile from glob import glob +from pathlib import Path from django.conf import settings from django.template import loader as template_loader @@ -395,6 +397,57 @@ def build(self): raise BuildEnvironmentError('No TeX files were found') # Run LaTeX -> PDF conversions + if self.project.has_feature(Feature.USE_PDF_LATEXMK): + return self._build_latexmk(cwd, latex_cwd) + + return self._build_pdflatex(tex_files, latex_cwd) + + def _build_latexmk(self, cwd, latex_cwd): + # These steps are copied from the Makefile generated by Sphinx >= 1.6 + # https://github.com/sphinx-doc/sphinx/blob/master/sphinx/texinputs/Makefile_t + latex_path = Path(latex_cwd) + images = [] + for extension in ('png', 'gif', 'jpg', 'jpeg'): + images.extend(latex_path.glob(f'*.{extension}')) + + # FIXME: instead of checking by language here, what we want to check if + # ``latex_engine`` is ``platex`` + pdfs = [] + if self.project.language == 'ja': + pdfs = latex_path.glob('*.pdf') + + for image in itertools.chain(images, pdfs): + self.run( + 'extractbb', + image.name, + cwd=latex_cwd, + record=False, + ) + + rcfile = 'latexmkrc' + if self.project.language == 'ja': + rcfile = 'latexmkjarc' + + cmd_ret = self.run( + 'latexmk', + '-r', + rcfile, + + # FIXME: check for platex here as well + '-pdfdvi' if self.project.language == 'ja' else '-pdf', + + '-dvi-', + '-ps-', + f'-jobname={self.project.slug}', + warn_only=True, + cwd=latex_cwd, + ) + + self.pdf_file_name = f'{self.project.slug}.pdf' + + return True # :) + + def _build_pdflatex(self, tex_files, latex_cwd): pdflatex_cmds = [ ['pdflatex', '-interaction=nonstopmode', tex_file] for tex_file in tex_files diff --git a/readthedocs/projects/models.py b/readthedocs/projects/models.py index 94f154861e1..0a23a333bb6 100644 --- a/readthedocs/projects/models.py +++ b/readthedocs/projects/models.py @@ -1314,10 +1314,12 @@ def add_features(sender, **kwargs): DONT_SHALLOW_CLONE = 'dont_shallow_clone' USE_TESTING_BUILD_IMAGE = 'use_testing_build_image' SHARE_SPHINX_DOCTREE = 'share_sphinx_doctree' + USE_PDF_LATEXMK = 'use_pdf_latexmk' FEATURES = ( (USE_SPHINX_LATEST, _('Use latest version of Sphinx')), (USE_SETUPTOOLS_LATEST, _('Use latest version of setuptools')), + (USE_PDF_LATEXMK, _('Use latexmk to build the PDF')), (ALLOW_DEPRECATED_WEBHOOKS, _('Allow deprecated webhook views')), (PIP_ALWAYS_UPGRADE, _('Always run pip install --upgrade')), (SKIP_SUBMODULES, _('Skip git submodule checkout')),