From 62e329dfa130d0af1fb2a0cfce483fad6df93475 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 22 Mar 2022 16:35:43 -0600 Subject: [PATCH 1/4] Do not write to the file unless there are changes. --- Tools/scripts/generate_global_objects.py | 40 +++++++++++++++++------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/Tools/scripts/generate_global_objects.py b/Tools/scripts/generate_global_objects.py index 17ddb8b324a0b6..244242d015e4a2 100644 --- a/Tools/scripts/generate_global_objects.py +++ b/Tools/scripts/generate_global_objects.py @@ -1,5 +1,6 @@ import contextlib import glob +import io import os.path import re import sys @@ -123,6 +124,7 @@ def iter_global_strings(): varname, string = m.groups() yield varname, string, filename, lno, line + def iter_to_marker(lines, marker): for line in lines: if line.rstrip() == marker: @@ -165,6 +167,18 @@ def block(self, prefix, suffix="", *, continuation=None): self.write("}" + suffix) +@contextlib.contextmanager +def open_for_changes(filename, orig): + outfile = io.StringIO() + yield outfile + text = outfile.getvalue() + if text != orig: + with open(filename, 'w', encoding='utf-8') as outfile: + outfile.write(text) + else: + print(f'# not changed: {filename}') + + ####################################### # the global objects @@ -177,13 +191,15 @@ def generate_global_strings(identifiers, strings): # Read the non-generated part of the file. with open(filename) as infile: - before = ''.join(iter_to_marker(infile, START))[:-1] - for _ in iter_to_marker(infile, END): - pass - after = infile.read()[:-1] + orig = infile.read() + lines = iter(orig.rstrip().splitlines()) + before = '\n'.join(iter_to_marker(lines, START)) + for _ in iter_to_marker(lines, END): + pass + after = '\n'.join(lines) # Generate the file. - with open(filename, 'w', encoding='utf-8') as outfile: + with open_for_changes(filename, orig) as outfile: printer = Printer(outfile) printer.write(before) printer.write(START) @@ -202,7 +218,6 @@ def generate_global_strings(identifiers, strings): with printer.block('struct', ' latin1[128];'): printer.write("PyCompactUnicodeObject _latin1;") printer.write("uint8_t _data[2];") - printer.write(END) printer.write(after) @@ -227,13 +242,15 @@ def generate_runtime_init(identifiers, strings): # Read the non-generated part of the file. with open(filename) as infile: - before = ''.join(iter_to_marker(infile, START))[:-1] - for _ in iter_to_marker(infile, END): - pass - after = infile.read()[:-1] + orig = infile.read() + lines = iter(orig.rstrip().splitlines()) + before = '\n'.join(iter_to_marker(lines, START)) + for _ in iter_to_marker(lines, END): + pass + after = '\n'.join(lines) # Generate the file. - with open(filename, 'w', encoding='utf-8') as outfile: + with open_for_changes(filename, orig) as outfile: printer = Printer(outfile) printer.write(before) printer.write(START) @@ -286,6 +303,7 @@ def get_identifiers_and_strings() -> 'tuple[set[str], dict[str, str]]': raise ValueError(f'string mismatch for {name!r} ({string!r} != {strings[name]!r}') return identifiers, strings + ####################################### # the script From 32f618c42743bb4e4428c4e573cf1f18fe291fb5 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 22 Mar 2022 16:36:23 -0600 Subject: [PATCH 2/4] Run regen-deepfreeze manually instead of as a dependency. --- Makefile.pre.in | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Makefile.pre.in b/Makefile.pre.in index c4034dc248c65b..32c433e6bbe822 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1179,7 +1179,12 @@ regen-importlib: regen-frozen # Global objects .PHONY: regen-global-objects -regen-global-objects: regen-deepfreeze $(srcdir)/Tools/scripts/generate_global_objects.py +regen-global-objects: $(srcdir)/Tools/scripts/generate_global_objects.py + $(PYTHON_FOR_REGEN) $(srcdir)/Tools/scripts/generate_global_objects.py + # Run one more time after deepfreezing, to catch any globals added + # there. This is necessary because the deep-frozen code isn't + # commited to the repo. + $(MAKE) regen-deepfreeze $(PYTHON_FOR_REGEN) $(srcdir)/Tools/scripts/generate_global_objects.py ############################################################################ From 9e3be6933f8fa822f5b18367233e902d16475949 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 22 Mar 2022 16:52:53 -0600 Subject: [PATCH 3/4] Add a docstring. --- Tools/scripts/generate_global_objects.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Tools/scripts/generate_global_objects.py b/Tools/scripts/generate_global_objects.py index 244242d015e4a2..f7653604e822b2 100644 --- a/Tools/scripts/generate_global_objects.py +++ b/Tools/scripts/generate_global_objects.py @@ -169,6 +169,7 @@ def block(self, prefix, suffix="", *, continuation=None): @contextlib.contextmanager def open_for_changes(filename, orig): + """Like open() but only write to the file if it changed.""" outfile = io.StringIO() yield outfile text = outfile.getvalue() From e9010c0d4891bf7896a9712bcc0fc364b0dfeb1e Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 22 Mar 2022 17:01:46 -0600 Subject: [PATCH 4/4] Hide the comments. --- Makefile.pre.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in index 32c433e6bbe822..873331e57ede29 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1181,9 +1181,9 @@ regen-importlib: regen-frozen .PHONY: regen-global-objects regen-global-objects: $(srcdir)/Tools/scripts/generate_global_objects.py $(PYTHON_FOR_REGEN) $(srcdir)/Tools/scripts/generate_global_objects.py - # Run one more time after deepfreezing, to catch any globals added - # there. This is necessary because the deep-frozen code isn't - # commited to the repo. + @# Run one more time after deepfreezing, to catch any globals added + @# there. This is necessary because the deep-frozen code isn't + @# commited to the repo. $(MAKE) regen-deepfreeze $(PYTHON_FOR_REGEN) $(srcdir)/Tools/scripts/generate_global_objects.py