mirror of
https://github.com/python/cpython.git
synced 2025-08-04 17:08:35 +00:00
gh-97669: Create Tools/build/ directory (#97963)
Create Tools/build/ directory. Move the following scripts from Tools/scripts/ to Tools/build/: * check_extension_modules.py * deepfreeze.py * freeze_modules.py * generate_global_objects.py * generate_levenshtein_examples.py * generate_opcode_h.py * generate_re_casefix.py * generate_sre_constants.py * generate_stdlib_module_names.py * generate_token.py * parse_html5_entities.py * smelly.py * stable_abi.py * umarshal.py * update_file.py * verify_ensurepip_wheels.py Update references to these scripts.
This commit is contained in:
parent
eae7dad402
commit
1863302d61
41 changed files with 102 additions and 84 deletions
92
Tools/build/update_file.py
Normal file
92
Tools/build/update_file.py
Normal file
|
@ -0,0 +1,92 @@
|
|||
"""
|
||||
A script that replaces an old file with a new one, only if the contents
|
||||
actually changed. If not, the new file is simply deleted.
|
||||
|
||||
This avoids wholesale rebuilds when a code (re)generation phase does not
|
||||
actually change the in-tree generated code.
|
||||
"""
|
||||
|
||||
import contextlib
|
||||
import os
|
||||
import os.path
|
||||
import sys
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def updating_file_with_tmpfile(filename, tmpfile=None):
|
||||
"""A context manager for updating a file via a temp file.
|
||||
|
||||
The context manager provides two open files: the source file open
|
||||
for reading, and the temp file, open for writing.
|
||||
|
||||
Upon exiting: both files are closed, and the source file is replaced
|
||||
with the temp file.
|
||||
"""
|
||||
# XXX Optionally use tempfile.TemporaryFile?
|
||||
if not tmpfile:
|
||||
tmpfile = filename + '.tmp'
|
||||
elif os.path.isdir(tmpfile):
|
||||
tmpfile = os.path.join(tmpfile, filename + '.tmp')
|
||||
|
||||
with open(filename, 'rb') as infile:
|
||||
line = infile.readline()
|
||||
|
||||
if line.endswith(b'\r\n'):
|
||||
newline = "\r\n"
|
||||
elif line.endswith(b'\r'):
|
||||
newline = "\r"
|
||||
elif line.endswith(b'\n'):
|
||||
newline = "\n"
|
||||
else:
|
||||
raise ValueError(f"unknown end of line: {filename}: {line!a}")
|
||||
|
||||
with open(tmpfile, 'w', newline=newline) as outfile:
|
||||
with open(filename) as infile:
|
||||
yield infile, outfile
|
||||
update_file_with_tmpfile(filename, tmpfile)
|
||||
|
||||
|
||||
def update_file_with_tmpfile(filename, tmpfile, *, create=False):
|
||||
try:
|
||||
targetfile = open(filename, 'rb')
|
||||
except FileNotFoundError:
|
||||
if not create:
|
||||
raise # re-raise
|
||||
outcome = 'created'
|
||||
os.replace(tmpfile, filename)
|
||||
else:
|
||||
with targetfile:
|
||||
old_contents = targetfile.read()
|
||||
with open(tmpfile, 'rb') as f:
|
||||
new_contents = f.read()
|
||||
# Now compare!
|
||||
if old_contents != new_contents:
|
||||
outcome = 'updated'
|
||||
os.replace(tmpfile, filename)
|
||||
else:
|
||||
outcome = 'same'
|
||||
os.unlink(tmpfile)
|
||||
return outcome
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--create', action='store_true')
|
||||
parser.add_argument('--exitcode', action='store_true')
|
||||
parser.add_argument('filename', help='path to be updated')
|
||||
parser.add_argument('tmpfile', help='path with new contents')
|
||||
args = parser.parse_args()
|
||||
kwargs = vars(args)
|
||||
setexitcode = kwargs.pop('exitcode')
|
||||
|
||||
outcome = update_file_with_tmpfile(**kwargs)
|
||||
if setexitcode:
|
||||
if outcome == 'same':
|
||||
sys.exit(0)
|
||||
elif outcome == 'updated':
|
||||
sys.exit(1)
|
||||
elif outcome == 'created':
|
||||
sys.exit(2)
|
||||
else:
|
||||
raise NotImplementedError
|
Loading…
Add table
Add a link
Reference in a new issue