Commit 14d26bc8 authored by Julien Muchembled's avatar Julien Muchembled

jinja2: try to not rewrite on update if there's no change

parent bafbc9d8
......@@ -27,6 +27,8 @@
import errno
import os
import json
import stat
import tempfile
import zc.buildout
from jinja2 import Environment, StrictUndefined, \
BaseLoader, TemplateNotFound, PrefixLoader
......@@ -128,6 +130,31 @@ LOADER_TYPE_DICT = {
'folder': (FolderLoader, getKey),
}
def get_mode(fd):
return stat.S_IMODE(os.fstat(fd).st_mode)
def get_umask():
global get_umask
while 1:
p = tempfile.mktemp()
try:
fd = os.open(p, os.O_CREAT | os.O_EXCL, 0o777)
break
except OSError as e:
if e.errno != errno.EEXIST:
if os.name == 'nt' and e.errno == errno.EACCES:
p = os.path.basename(p)
if os.path.isdir(p) and os.access(p, os.W_OK):
continue
raise
try:
os.unlink(p)
umask = get_mode(fd)
finally:
os.close(fd)
get_umask = lambda: umask
return umask
class Recipe(object):
def __init__(self, buildout, name, options):
......@@ -200,6 +227,20 @@ class Recipe(object):
env.compile(source, filename=template),
env.make_globals(None), None)
rendered = template.render(**self.context).encode(self.encoding)
mode = self.mode
mask = (0o777 if rendered.startswith(b'#!') else 0o666
) if mode is None else 0
# Try to reuse existing file. This is particularly
# important to avoid excessive IO because we render on update.
try:
with open(self.rendered, 'rb') as f:
if f.read(len(rendered)+1) == rendered:
m = get_umask() & mask if mode is None else mode
if get_mode(f.fileno()) != m:
os.fchmod(f.fileno(), m)
return self.rendered
except (IOError, OSError) as e:
pass
# Unlink any existing file so that umask applies.
try:
os.unlink(self.rendered)
......@@ -209,10 +250,7 @@ class Recipe(object):
outdir = os.path.dirname(self.rendered)
if outdir and not os.path.exists(outdir):
os.makedirs(outdir)
mode = self.mode
fd = os.open(self.rendered, os.O_CREAT | os.O_EXCL | os.O_WRONLY,
(0o777 if rendered.startswith(b'#!') else 0o666)
if mode is None else 0)
fd = os.open(self.rendered, os.O_CREAT | os.O_EXCL | os.O_WRONLY, mask)
try:
os.write(fd, rendered)
if mode is not None:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment