Fix #4362: latex: Don't overwrite .tex file if document not changed

This commit is contained in:
Takeshi KOMIYA 2018-06-13 23:26:42 +09:00
parent 2855721d0b
commit 28fe6dadf4
4 changed files with 57 additions and 6 deletions

View File

@ -137,6 +137,7 @@ Features added
* html: Output ``canonical_url`` metadata if :confval:`html_baseurl` set (refs:
#4193)
* #5029: autosummary: expose ``inherited_members`` to template
* #4362: latex: Don't overwrite .tex file if document not changed
Bugs fixed
----------

View File

@ -13,7 +13,6 @@ import os
from os import path
from docutils.frontend import OptionParser
from docutils.io import FileOutput
from six import text_type
from sphinx import package_dir, addnodes, highlighting
@ -31,7 +30,7 @@ from sphinx.locale import _, __
from sphinx.transforms import SphinxTransformer
from sphinx.util import texescape, logging, status_iterator
from sphinx.util.console import bold, darkgreen # type: ignore
from sphinx.util.docutils import new_document
from sphinx.util.docutils import SphinxFileOutput, new_document
from sphinx.util.fileutil import copy_asset_file
from sphinx.util.nodes import inline_all_toctrees
from sphinx.util.osutil import SEP, make_filename
@ -134,9 +133,8 @@ class LaTeXBuilder(Builder):
toctree_only = False
if len(entry) > 5:
toctree_only = entry[5]
destination = FileOutput(
destination_path=path.join(self.outdir, targetname),
encoding='utf-8')
destination = SphinxFileOutput(destination_path=path.join(self.outdir, targetname),
encoding='utf-8', overwrite_if_changed=True)
logger.info(__("processing %s..."), targetname, nonl=1)
toctrees = self.env.get_doctree(docname).traverse(addnodes.toctree)
if toctrees:

View File

@ -10,6 +10,7 @@
"""
from __future__ import absolute_import
import codecs
import os
import re
import types
@ -21,6 +22,7 @@ from os import path
import docutils
from docutils import nodes
from docutils.io import FileOutput
from docutils.parsers.rst import Directive, directives, roles, convert_directive_function
from docutils.statemachine import StateMachine
from docutils.utils import Reporter
@ -300,6 +302,26 @@ def switch_source_input(state, content):
state.memo.reporter.get_source_and_line = get_source_and_line
class SphinxFileOutput(FileOutput):
"""Better FileOutput class for Sphinx."""
def __init__(self, **kwargs):
# type: (Any) -> None
self.overwrite_if_changed = kwargs.pop('overwrite_if_changed', False)
FileOutput.__init__(self, **kwargs)
def write(self, data):
# type: (unicode) -> unicode
if (self.destination_path and self.autoclose and 'b' not in self.mode and
self.overwrite_if_changed and os.path.exists(self.destination_path)):
with codecs.open(self.destination_path, encoding=self.encoding) as f:
# skip writing: content not changed
if f.read() == data:
return data
return FileOutput.write(self, data)
class SphinxDirective(Directive):
"""A base class for Sphinx directives.

View File

@ -9,9 +9,11 @@
:license: BSD, see LICENSE for details.
"""
import os
from docutils import nodes
from sphinx.util.docutils import docutils_namespace, register_node
from sphinx.util.docutils import SphinxFileOutput, docutils_namespace, register_node
def test_register_node():
@ -32,3 +34,31 @@ def test_register_node():
assert not hasattr(nodes.GenericNodeVisitor, 'depart_custom_node')
assert not hasattr(nodes.SparseNodeVisitor, 'visit_custom_node')
assert not hasattr(nodes.SparseNodeVisitor, 'depart_custom_node')
def test_SphinxFileOutput(tmpdir):
content = 'Hello Sphinx World'
# write test.txt at first
filename = str(tmpdir / 'test.txt')
output = SphinxFileOutput(destination_path=filename)
output.write(content)
os.utime(filename, (0, 0))
# overrite it again
output.write(content)
assert os.stat(filename).st_mtime != 0 # updated
# write test2.txt at first
filename = str(tmpdir / 'test2.txt')
output = SphinxFileOutput(destination_path=filename, overwrite_if_changed=True)
output.write(content)
os.utime(filename, (0, 0))
# overrite it again
output.write(content)
assert os.stat(filename).st_mtime == 0 # not updated
# overrite it again (content changed)
output.write(content + "; content change")
assert os.stat(filename).st_mtime != 0 # updated