# HG changeset patch # User Gregory Szorc # Date 2017-12-04 04:55:35 # Node ID 61ff0d7d56fd0c70894c94cf14beb610c8080c21 # Parent 04a2820f2fca35ea563198dc67cca1a52ab54b9d 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 diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -136,6 +136,18 @@ from distutils.errors import ( 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 @@ elif os.path.exists('.hg_archival.txt'): 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 @@ class hgbuildpy(build_py): 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)