From 02d2888e6250a5ec9bdcc9ff1850b709081b3511 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 c5a664835fa..d439148a4a1 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 @@ -392,6 +394,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 5991a41bb14..58037291f18 100644 --- a/readthedocs/projects/models.py +++ b/readthedocs/projects/models.py @@ -1313,10 +1313,12 @@ def add_features(sender, **kwargs): API_LARGE_DATA = 'api_large_data' DONT_SHALLOW_CLONE = 'dont_shallow_clone' USE_TESTING_BUILD_IMAGE = 'use_testing_build_image' + 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')), (