git-p4: pre-compile RCS keyword regexes

Previously git-p4.py would compile one of two regular expressions for ever RCS keyword-enabled file. This patch improves simplifies the code by pre-compiling the two regular expressions when the script first loads. Signed-off-by: Joel Holdsworth <jholdsworth@nvidia.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Joel Holdsworth committed Dec 16, 2021 at 13:46 UTC e665e98ec1d1558a55a3e7e5fd5e88d70396ec96
1 file changed +18 -30
git-p4.py
+18 -30
@@ -56,6 +56,9 @@ defaultBlockSize = 1<<20
56
57 p4_access_checked = False
58
59 +re_ko_keywords = re.compile(r'\$(Id|Header)(:[^$\n]+)?\$')
60 +re_k_keywords = re.compile(r'\$(Id|Header|Author|Date|DateTime|Change|File|Revision)(:[^$\n]+)?\$')
61 +
62 def p4_build_cmd(cmd):
63 """Build a suitable p4 command line.
64
@@ -577,20 +580,12 @@ def p4_type(f):
580 #
581 def p4_keywords_regexp_for_type(base, type_mods):
582 if base in ("text", "unicode", "binary"):
580 - kwords = None
583 if "ko" in type_mods:
582 - kwords = 'Id|Header'
584 + return re_ko_keywords
585 elif "k" in type_mods:
584 - kwords = 'Id|Header|Author|Date|DateTime|Change|File|Revision'
586 + return re_k_keywords
587 else:
588 return None
587 - pattern = r"""
588 - \$ # Starts with a dollar, followed by...
589 - (%s) # one of the keywords, followed by...
590 - (:[^$\n]+)? # possibly an old expansion, followed by...
591 - \$ # another dollar
592 - """ % kwords
593 - return pattern
589 else:
590 return None
591
@@ -1753,15 +1748,13 @@ class P4Submit(Command, P4UserMap):
1748
1749 return result
1750
1756 - def patchRCSKeywords(self, file, pattern):
1757 - # Attempt to zap the RCS keywords in a p4 controlled file matching the given pattern
1751 + def patchRCSKeywords(self, file, regexp):
1752 + # Attempt to zap the RCS keywords in a p4 controlled file matching the given regex
1753 (handle, outFileName) = tempfile.mkstemp(dir='.')
1754 try:
1755 with os.fdopen(handle, "w+") as outFile, open(file, "r") as inFile:
1761 - regexp = re.compile(pattern, re.VERBOSE)
1756 for line in inFile.readlines():
1763 - line = regexp.sub(r'$\1$', line)
1764 - outFile.write(line)
1757 + outFile.write(regexp.sub(r'$\1$', line))
1758 # Forcibly overwrite the original file
1759 os.unlink(file)
1760 shutil.move(outFileName, file)
@@ -2088,25 +2081,22 @@ class P4Submit(Command, P4UserMap):
2081 # the patch to see if that's possible.
2082 if gitConfigBool("git-p4.attemptRCSCleanup"):
2083 file = None
2091 - pattern = None
2084 kwfiles = {}
2085 for file in editedFiles | filesToDelete:
2086 # did this file's delta contain RCS keywords?
2095 - pattern = p4_keywords_regexp_for_file(file)
2096 -
2097 - if pattern:
2087 + regexp = p4_keywords_regexp_for_file(file)
2088 + if regexp:
2089 # this file is a possibility...look for RCS keywords.
2099 - regexp = re.compile(pattern, re.VERBOSE)
2090 for line in read_pipe_lines(["git", "diff", "%s^..%s" % (id, id), file]):
2091 if regexp.search(line):
2092 if verbose:
2103 - print("got keyword match on %s in %s in %s" % (pattern, line, file))
2104 - kwfiles[file] = pattern
2093 + print("got keyword match on %s in %s in %s" % (regex.pattern, line, file))
2094 + kwfiles[file] = regexp
2095 break
2096
2107 - for file in kwfiles:
2097 + for file, regexp in kwfiles.items():
2098 if verbose:
2109 - print("zapping %s with %s" % (line,pattern))
2099 + print("zapping %s with %s" % (line, regexp.pattern))
2100 # File is being deleted, so not open in p4. Must
2101 # disable the read-only bit on windows.
2102 if self.isWindows and file not in editedFiles:
@@ -3026,12 +3016,10 @@ class P4Sync(Command, P4UserMap):
3016
3017 # Note that we do not try to de-mangle keywords on utf16 files,
3018 # even though in theory somebody may want that.
3029 - pattern = p4_keywords_regexp_for_type(type_base, type_mods)
3030 - if pattern:
3031 - regexp = re.compile(pattern, re.VERBOSE)
3032 - text = ''.join(decode_text_stream(c) for c in contents)
3033 - text = regexp.sub(r'$\1$', text)
3034 - contents = [ encode_text_stream(text) ]
3019 + regexp = p4_keywords_regexp_for_type(type_base, type_mods)
3020 + if regexp:
3021 + contents = [encode_text_stream(regexp.sub(
3022 + r'$\1$', ''.join(decode_text_stream(c) for c in contents)))]
3023
3024 if self.largeFileSystem:
3025 (git_mode, contents) = self.largeFileSystem.processContent(git_mode, relPath, contents)