mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2026-09-03 20:52:55 -05:00
Merge branch 'FileAvoidWrite'
This commit is contained in:
@@ -51,6 +51,7 @@ Other contributors, listed alphabetically, are:
|
|||||||
* Jeppe Pihl -- literalinclude improvements
|
* Jeppe Pihl -- literalinclude improvements
|
||||||
* Rob Ruana -- napoleon extension
|
* Rob Ruana -- napoleon extension
|
||||||
* Stefan Seefeld -- toctree improvements
|
* Stefan Seefeld -- toctree improvements
|
||||||
|
* Gregory Szorc -- performance improvements
|
||||||
* Shibukawa Yoshiki -- pluggable search API and Japanese search
|
* Shibukawa Yoshiki -- pluggable search API and Japanese search
|
||||||
* Taku Shimizu -- epub3 builder
|
* Taku Shimizu -- epub3 builder
|
||||||
* Antonio Valentino -- qthelp builder
|
* Antonio Valentino -- qthelp builder
|
||||||
|
|||||||
@@ -98,6 +98,9 @@ Features added
|
|||||||
* C++, added concept directive. Thanks to mickk-on-cpp.
|
* C++, added concept directive. Thanks to mickk-on-cpp.
|
||||||
* C++, added support for template introduction syntax. Thanks to mickk-on-cpp.
|
* C++, added support for template introduction syntax. Thanks to mickk-on-cpp.
|
||||||
* #2725: latex builder: allow to use user-defined template file (experimental)
|
* #2725: latex builder: allow to use user-defined template file (experimental)
|
||||||
|
* apidoc now avoids invalidating cached files by not writing to files whose
|
||||||
|
content doesn't change. This can lead to significant performance wins if
|
||||||
|
apidoc is run frequently.
|
||||||
|
|
||||||
Bugs fixed
|
Bugs fixed
|
||||||
----------
|
----------
|
||||||
|
|||||||
+2
-2
@@ -22,7 +22,7 @@ import optparse
|
|||||||
from os import path
|
from os import path
|
||||||
from six import binary_type
|
from six import binary_type
|
||||||
|
|
||||||
from sphinx.util.osutil import walk
|
from sphinx.util.osutil import FileAvoidWrite, walk
|
||||||
from sphinx import __display_version__
|
from sphinx import __display_version__
|
||||||
|
|
||||||
# automodule options
|
# automodule options
|
||||||
@@ -62,7 +62,7 @@ def write_file(name, text, opts):
|
|||||||
print('File %s already exists, skipping.' % fname)
|
print('File %s already exists, skipping.' % fname)
|
||||||
else:
|
else:
|
||||||
print('Creating file %s.' % fname)
|
print('Creating file %s.' % fname)
|
||||||
with open(fname, 'w') as f:
|
with FileAvoidWrite(fname) as f:
|
||||||
f.write(text)
|
f.write(text)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import shutil
|
|||||||
import filecmp
|
import filecmp
|
||||||
from os import path
|
from os import path
|
||||||
import contextlib
|
import contextlib
|
||||||
|
from io import BytesIO, StringIO
|
||||||
|
|
||||||
from six import PY2, text_type
|
from six import PY2, text_type
|
||||||
|
|
||||||
@@ -219,6 +220,73 @@ def cd(target_dir):
|
|||||||
os.chdir(cwd)
|
os.chdir(cwd)
|
||||||
|
|
||||||
|
|
||||||
|
class FileAvoidWrite(object):
|
||||||
|
"""File-like object that buffers output and only writes if content changed.
|
||||||
|
|
||||||
|
Use this class like when writing to a file to avoid touching the original
|
||||||
|
file if the content hasn't changed. This is useful in scenarios where file
|
||||||
|
mtime is used to invalidate caches or trigger new behavior.
|
||||||
|
|
||||||
|
When writing to this file handle, all writes are buffered until the object
|
||||||
|
is closed.
|
||||||
|
|
||||||
|
Objects can be used as context managers.
|
||||||
|
"""
|
||||||
|
def __init__(self, path):
|
||||||
|
self._path = path
|
||||||
|
self._io = None
|
||||||
|
|
||||||
|
def write(self, data):
|
||||||
|
if not self._io:
|
||||||
|
if isinstance(data, text_type):
|
||||||
|
self._io = StringIO()
|
||||||
|
else:
|
||||||
|
self._io = BytesIO()
|
||||||
|
|
||||||
|
self._io.write(data)
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
"""Stop accepting writes and write file, if needed."""
|
||||||
|
if not self._io:
|
||||||
|
raise Exception('FileAvoidWrite does not support empty files.')
|
||||||
|
|
||||||
|
buf = self.getvalue()
|
||||||
|
self._io.close()
|
||||||
|
|
||||||
|
r_mode = 'r'
|
||||||
|
w_mode = 'w'
|
||||||
|
if isinstance(self._io, BytesIO):
|
||||||
|
r_mode = 'rb'
|
||||||
|
w_mode = 'wb'
|
||||||
|
|
||||||
|
old_content = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(self._path, r_mode) as old_f:
|
||||||
|
old_content = old_f.read()
|
||||||
|
if old_content == buf:
|
||||||
|
return
|
||||||
|
except IOError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
with open(self._path, w_mode) as f:
|
||||||
|
f.write(buf)
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, type, value, traceback):
|
||||||
|
self.close()
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
# Proxy to _io instance.
|
||||||
|
if not self._io:
|
||||||
|
raise Exception('Must write to FileAvoidWrite before other '
|
||||||
|
'methods can be used')
|
||||||
|
|
||||||
|
return getattr(self._io, name)
|
||||||
|
|
||||||
|
|
||||||
def rmtree(path):
|
def rmtree(path):
|
||||||
if os.path.isdir(path):
|
if os.path.isdir(path):
|
||||||
shutil.rmtree(path)
|
shutil.rmtree(path)
|
||||||
|
|||||||
Reference in New Issue
Block a user