|
10 | 10 |
|
11 | 11 | import optparse, sys, os, marshal, subprocess, shelve
|
12 | 12 | import tempfile, getopt, os.path, time, platform
|
13 |
| -import re |
| 13 | +import re, shutil |
14 | 14 |
|
15 | 15 | verbose = False
|
16 | 16 |
|
@@ -186,6 +186,47 @@ def split_p4_type(p4type):
|
186 | 186 | mods = s[1]
|
187 | 187 | return (base, mods)
|
188 | 188 |
|
| 189 | +# |
| 190 | +# return the raw p4 type of a file (text, text+ko, etc) |
| 191 | +# |
| 192 | +def p4_type(file): |
| 193 | + results = p4CmdList(["fstat", "-T", "headType", file]) |
| 194 | + return results[0]['headType'] |
| 195 | + |
| 196 | +# |
| 197 | +# Given a type base and modifier, return a regexp matching |
| 198 | +# the keywords that can be expanded in the file |
| 199 | +# |
| 200 | +def p4_keywords_regexp_for_type(base, type_mods): |
| 201 | + if base in ("text", "unicode", "binary"): |
| 202 | + kwords = None |
| 203 | + if "ko" in type_mods: |
| 204 | + kwords = 'Id|Header' |
| 205 | + elif "k" in type_mods: |
| 206 | + kwords = 'Id|Header|Author|Date|DateTime|Change|File|Revision' |
| 207 | + else: |
| 208 | + return None |
| 209 | + pattern = r""" |
| 210 | + \$ # Starts with a dollar, followed by... |
| 211 | + (%s) # one of the keywords, followed by... |
| 212 | + (:[^$]+)? # possibly an old expansion, followed by... |
| 213 | + \$ # another dollar |
| 214 | + """ % kwords |
| 215 | + return pattern |
| 216 | + else: |
| 217 | + return None |
| 218 | + |
| 219 | +# |
| 220 | +# Given a file, return a regexp matching the possible |
| 221 | +# RCS keywords that will be expanded, or None for files |
| 222 | +# with kw expansion turned off. |
| 223 | +# |
| 224 | +def p4_keywords_regexp_for_file(file): |
| 225 | + if not os.path.exists(file): |
| 226 | + return None |
| 227 | + else: |
| 228 | + (type_base, type_mods) = split_p4_type(p4_type(file)) |
| 229 | + return p4_keywords_regexp_for_type(type_base, type_mods) |
189 | 230 |
|
190 | 231 | def setP4ExecBit(file, mode):
|
191 | 232 | # Reopens an already open file and changes the execute bit to match
|
@@ -753,6 +794,29 @@ class P4Submit(Command, P4UserMap):
|
753 | 794 |
|
754 | 795 | return result
|
755 | 796 |
|
| 797 | + def patchRCSKeywords(self, file, pattern): |
| 798 | + # Attempt to zap the RCS keywords in a p4 controlled file matching the given pattern |
| 799 | + (handle, outFileName) = tempfile.mkstemp(dir='.') |
| 800 | + try: |
| 801 | + outFile = os.fdopen(handle, "w+") |
| 802 | + inFile = open(file, "r") |
| 803 | + regexp = re.compile(pattern, re.VERBOSE) |
| 804 | + for line in inFile.readlines(): |
| 805 | + line = regexp.sub(r'$\1$', line) |
| 806 | + outFile.write(line) |
| 807 | + inFile.close() |
| 808 | + outFile.close() |
| 809 | + # Forcibly overwrite the original file |
| 810 | + os.unlink(file) |
| 811 | + shutil.move(outFileName, file) |
| 812 | + except: |
| 813 | + # cleanup our temporary file |
| 814 | + os.unlink(outFileName) |
| 815 | + print "Failed to strip RCS keywords in %s" % file |
| 816 | + raise |
| 817 | + |
| 818 | + print "Patched up RCS keywords in %s" % file |
| 819 | + |
756 | 820 | def p4UserForCommit(self,id):
|
757 | 821 | # Return the tuple (perforce user,git email) for a given git commit id
|
758 | 822 | self.getUserMapFromPerforceServer()
|
@@ -918,6 +982,7 @@ class P4Submit(Command, P4UserMap):
|
918 | 982 | filesToDelete = set()
|
919 | 983 | editedFiles = set()
|
920 | 984 | filesToChangeExecBit = {}
|
| 985 | + |
921 | 986 | for line in diff:
|
922 | 987 | diff = parseDiffTreeEntry(line)
|
923 | 988 | modifier = diff['status']
|
@@ -964,9 +1029,45 @@ class P4Submit(Command, P4UserMap):
|
964 | 1029 | patchcmd = diffcmd + " | git apply "
|
965 | 1030 | tryPatchCmd = patchcmd + "--check -"
|
966 | 1031 | applyPatchCmd = patchcmd + "--check --apply -"
|
| 1032 | + patch_succeeded = True |
967 | 1033 |
|
968 | 1034 | if os.system(tryPatchCmd) != 0:
|
| 1035 | + fixed_rcs_keywords = False |
| 1036 | + patch_succeeded = False |
969 | 1037 | print "Unfortunately applying the change failed!"
|
| 1038 | + |
| 1039 | + # Patch failed, maybe it's just RCS keyword woes. Look through |
| 1040 | + # the patch to see if that's possible. |
| 1041 | + if gitConfig("git-p4.attemptRCSCleanup","--bool") == "true": |
| 1042 | + file = None |
| 1043 | + pattern = None |
| 1044 | + kwfiles = {} |
| 1045 | + for file in editedFiles | filesToDelete: |
| 1046 | + # did this file's delta contain RCS keywords? |
| 1047 | + pattern = p4_keywords_regexp_for_file(file) |
| 1048 | + |
| 1049 | + if pattern: |
| 1050 | + # this file is a possibility...look for RCS keywords. |
| 1051 | + regexp = re.compile(pattern, re.VERBOSE) |
| 1052 | + for line in read_pipe_lines(["git", "diff", "%s^..%s" % (id, id), file]): |
| 1053 | + if regexp.search(line): |
| 1054 | + if verbose: |
| 1055 | + print "got keyword match on %s in %s in %s" % (pattern, line, file) |
| 1056 | + kwfiles[file] = pattern |
| 1057 | + break |
| 1058 | + |
| 1059 | + for file in kwfiles: |
| 1060 | + if verbose: |
| 1061 | + print "zapping %s with %s" % (line,pattern) |
| 1062 | + self.patchRCSKeywords(file, kwfiles[file]) |
| 1063 | + fixed_rcs_keywords = True |
| 1064 | + |
| 1065 | + if fixed_rcs_keywords: |
| 1066 | + print "Retrying the patch with RCS keywords cleaned up" |
| 1067 | + if os.system(tryPatchCmd) == 0: |
| 1068 | + patch_succeeded = True |
| 1069 | + |
| 1070 | + if not patch_succeeded: |
970 | 1071 | print "What do you want to do?"
|
971 | 1072 | response = "x"
|
972 | 1073 | while response != "s" and response != "a" and response != "w":
|
@@ -1585,15 +1686,12 @@ class P4Sync(Command, P4UserMap):
|
1585 | 1686 |
|
1586 | 1687 | # Note that we do not try to de-mangle keywords on utf16 files,
|
1587 | 1688 | # even though in theory somebody may want that.
|
1588 |
| - if type_base in ("text", "unicode", "binary"): |
1589 |
| - if "ko" in type_mods: |
1590 |
| - text = ''.join(contents) |
1591 |
| - text = re.sub(r'\$(Id|Header):[^$]*\$', r'$\1$', text) |
1592 |
| - contents = [ text ] |
1593 |
| - elif "k" in type_mods: |
1594 |
| - text = ''.join(contents) |
1595 |
| - text = re.sub(r'\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$]*\$', r'$\1$', text) |
1596 |
| - contents = [ text ] |
| 1689 | + pattern = p4_keywords_regexp_for_type(type_base, type_mods) |
| 1690 | + if pattern: |
| 1691 | + regexp = re.compile(pattern, re.VERBOSE) |
| 1692 | + text = ''.join(contents) |
| 1693 | + text = regexp.sub(r'$\1$', text) |
| 1694 | + contents = [ text ] |
1597 | 1695 |
|
1598 | 1696 | self.gitStream.write("M %s inline %s\n" % (git_mode, relPath))
|
1599 | 1697 |
|
|
0 commit comments