mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge branch 'FileAvoidWrite'
This commit is contained in:
commit
e0d2783c7b
1
AUTHORS
1
AUTHORS
@ -51,6 +51,7 @@ Other contributors, listed alphabetically, are:
|
||||
* Jeppe Pihl -- literalinclude improvements
|
||||
* Rob Ruana -- napoleon extension
|
||||
* Stefan Seefeld -- toctree improvements
|
||||
* Gregory Szorc -- performance improvements
|
||||
* Shibukawa Yoshiki -- pluggable search API and Japanese search
|
||||
* Taku Shimizu -- epub3 builder
|
||||
* Antonio Valentino -- qthelp builder
|
||||
|
3
CHANGES
3
CHANGES
@ -98,6 +98,9 @@ Features added
|
||||
* C++, added concept directive. 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)
|
||||
* 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
|
||||
----------
|
||||
|
@ -22,7 +22,7 @@ import optparse
|
||||
from os import path
|
||||
from six import binary_type
|
||||
|
||||
from sphinx.util.osutil import walk
|
||||
from sphinx.util.osutil import FileAvoidWrite, walk
|
||||
from sphinx import __display_version__
|
||||
|
||||
# automodule options
|
||||
@ -62,7 +62,7 @@ def write_file(name, text, opts):
|
||||
print('File %s already exists, skipping.' % fname)
|
||||
else:
|
||||
print('Creating file %s.' % fname)
|
||||
with open(fname, 'w') as f:
|
||||
with FileAvoidWrite(fname) as f:
|
||||
f.write(text)
|
||||
|
||||
|
||||
|
@ -20,6 +20,7 @@ import shutil
|
||||
import filecmp
|
||||
from os import path
|
||||
import contextlib
|
||||
from io import BytesIO, StringIO
|
||||
|
||||
from six import PY2, text_type
|
||||
|
||||
@ -219,6 +220,73 @@ def cd(target_dir):
|
||||
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):
|
||||
if os.path.isdir(path):
|
||||
shutil.rmtree(path)
|
||||
|
Loading…
Reference in New Issue
Block a user