setup: only write some autogenerated files if they change
Without this change, setup.py always writes some files on every
invocation. This prevents some builds from being a no-op when they
should. And, since times can sneak into generated .pyc files,
this prevents file content from being deterministic between
builds.
As part of the refactor, we treat file content as bytes.
The only potential regression from this would be if some tool
is looking at mtimes of the changed files to determine if
further action should be taken. But I don't think anything
critically important is keyed off the mtimes of these specific files.
Differential Revision: https://phab.mercurial-scm.org/D1580
--- a/setup.py Mon Dec 04 15:30:30 2017 -0500
+++ b/setup.py Sun Dec 03 20:55:35 2017 -0800
@@ -136,6 +136,18 @@
from distutils.sysconfig import get_python_inc, get_config_var
from distutils.version import StrictVersion
+def write_if_changed(path, content):
+ """Write content to a file iff the content hasn't changed."""
+ if os.path.exists(path):
+ with open(path, 'rb') as fh:
+ current = fh.read()
+ else:
+ current = b''
+
+ if current != content:
+ with open(path, 'wb') as fh:
+ fh.write(content)
+
scripts = ['hg']
if os.name == 'nt':
# We remove hg.bat if we are able to build hg.exe.
@@ -317,9 +329,14 @@
version = kw.get('node', '')[:12]
if version:
- with open("mercurial/__version__.py", "w") as f:
- f.write('# this file is autogenerated by setup.py\n')
- f.write('version = "%s"\n' % version)
+ versionb = version
+ if not isinstance(versionb, bytes):
+ versionb = versionb.encode('ascii')
+
+ write_if_changed('mercurial/__version__.py', b''.join([
+ b'# this file is autogenerated by setup.py\n'
+ b'version = "%s"\n' % versionb,
+ ]))
try:
oldpolicy = os.environ.get('HGMODULEPOLICY', None)
@@ -478,9 +495,13 @@
modulepolicy = 'allow'
else:
modulepolicy = 'c'
- with open(os.path.join(basepath, '__modulepolicy__.py'), "w") as f:
- f.write('# this file is autogenerated by setup.py\n')
- f.write('modulepolicy = b"%s"\n' % modulepolicy)
+
+ content = b''.join([
+ b'# this file is autogenerated by setup.py\n',
+ b'modulepolicy = b"%s"\n' % modulepolicy.encode('ascii'),
+ ])
+ write_if_changed(os.path.join(basepath, '__modulepolicy__.py'),
+ content)
build_py.run(self)