Merge branch 'ld/git-p4-expanded-keywords'
* ld/git-p4-expanded-keywords: : Teach git-p4 to unexpand $RCS$-like keywords that are embedded in : tracked contents in order to reduce unnecessary merge conflicts. git-p4: add initial support for RCS keywords
This commit is contained in:
@ -10,7 +10,7 @@
|
||||
|
||||
import optparse, sys, os, marshal, subprocess, shelve
|
||||
import tempfile, getopt, os.path, time, platform
|
||||
import re
|
||||
import re, shutil
|
||||
|
||||
verbose = False
|
||||
|
||||
@ -186,6 +186,47 @@ def split_p4_type(p4type):
|
||||
mods = s[1]
|
||||
return (base, mods)
|
||||
|
||||
#
|
||||
# return the raw p4 type of a file (text, text+ko, etc)
|
||||
#
|
||||
def p4_type(file):
|
||||
results = p4CmdList(["fstat", "-T", "headType", file])
|
||||
return results[0]['headType']
|
||||
|
||||
#
|
||||
# Given a type base and modifier, return a regexp matching
|
||||
# the keywords that can be expanded in the file
|
||||
#
|
||||
def p4_keywords_regexp_for_type(base, type_mods):
|
||||
if base in ("text", "unicode", "binary"):
|
||||
kwords = None
|
||||
if "ko" in type_mods:
|
||||
kwords = 'Id|Header'
|
||||
elif "k" in type_mods:
|
||||
kwords = 'Id|Header|Author|Date|DateTime|Change|File|Revision'
|
||||
else:
|
||||
return None
|
||||
pattern = r"""
|
||||
\$ # Starts with a dollar, followed by...
|
||||
(%s) # one of the keywords, followed by...
|
||||
(:[^$]+)? # possibly an old expansion, followed by...
|
||||
\$ # another dollar
|
||||
""" % kwords
|
||||
return pattern
|
||||
else:
|
||||
return None
|
||||
|
||||
#
|
||||
# Given a file, return a regexp matching the possible
|
||||
# RCS keywords that will be expanded, or None for files
|
||||
# with kw expansion turned off.
|
||||
#
|
||||
def p4_keywords_regexp_for_file(file):
|
||||
if not os.path.exists(file):
|
||||
return None
|
||||
else:
|
||||
(type_base, type_mods) = split_p4_type(p4_type(file))
|
||||
return p4_keywords_regexp_for_type(type_base, type_mods)
|
||||
|
||||
def setP4ExecBit(file, mode):
|
||||
# Reopens an already open file and changes the execute bit to match
|
||||
@ -753,6 +794,29 @@ class P4Submit(Command, P4UserMap):
|
||||
|
||||
return result
|
||||
|
||||
def patchRCSKeywords(self, file, pattern):
|
||||
# Attempt to zap the RCS keywords in a p4 controlled file matching the given pattern
|
||||
(handle, outFileName) = tempfile.mkstemp(dir='.')
|
||||
try:
|
||||
outFile = os.fdopen(handle, "w+")
|
||||
inFile = open(file, "r")
|
||||
regexp = re.compile(pattern, re.VERBOSE)
|
||||
for line in inFile.readlines():
|
||||
line = regexp.sub(r'$\1$', line)
|
||||
outFile.write(line)
|
||||
inFile.close()
|
||||
outFile.close()
|
||||
# Forcibly overwrite the original file
|
||||
os.unlink(file)
|
||||
shutil.move(outFileName, file)
|
||||
except:
|
||||
# cleanup our temporary file
|
||||
os.unlink(outFileName)
|
||||
print "Failed to strip RCS keywords in %s" % file
|
||||
raise
|
||||
|
||||
print "Patched up RCS keywords in %s" % file
|
||||
|
||||
def p4UserForCommit(self,id):
|
||||
# Return the tuple (perforce user,git email) for a given git commit id
|
||||
self.getUserMapFromPerforceServer()
|
||||
@ -918,6 +982,7 @@ class P4Submit(Command, P4UserMap):
|
||||
filesToDelete = set()
|
||||
editedFiles = set()
|
||||
filesToChangeExecBit = {}
|
||||
|
||||
for line in diff:
|
||||
diff = parseDiffTreeEntry(line)
|
||||
modifier = diff['status']
|
||||
@ -964,9 +1029,45 @@ class P4Submit(Command, P4UserMap):
|
||||
patchcmd = diffcmd + " | git apply "
|
||||
tryPatchCmd = patchcmd + "--check -"
|
||||
applyPatchCmd = patchcmd + "--check --apply -"
|
||||
patch_succeeded = True
|
||||
|
||||
if os.system(tryPatchCmd) != 0:
|
||||
fixed_rcs_keywords = False
|
||||
patch_succeeded = False
|
||||
print "Unfortunately applying the change failed!"
|
||||
|
||||
# Patch failed, maybe it's just RCS keyword woes. Look through
|
||||
# the patch to see if that's possible.
|
||||
if gitConfig("git-p4.attemptRCSCleanup","--bool") == "true":
|
||||
file = None
|
||||
pattern = None
|
||||
kwfiles = {}
|
||||
for file in editedFiles | filesToDelete:
|
||||
# did this file's delta contain RCS keywords?
|
||||
pattern = p4_keywords_regexp_for_file(file)
|
||||
|
||||
if pattern:
|
||||
# this file is a possibility...look for RCS keywords.
|
||||
regexp = re.compile(pattern, re.VERBOSE)
|
||||
for line in read_pipe_lines(["git", "diff", "%s^..%s" % (id, id), file]):
|
||||
if regexp.search(line):
|
||||
if verbose:
|
||||
print "got keyword match on %s in %s in %s" % (pattern, line, file)
|
||||
kwfiles[file] = pattern
|
||||
break
|
||||
|
||||
for file in kwfiles:
|
||||
if verbose:
|
||||
print "zapping %s with %s" % (line,pattern)
|
||||
self.patchRCSKeywords(file, kwfiles[file])
|
||||
fixed_rcs_keywords = True
|
||||
|
||||
if fixed_rcs_keywords:
|
||||
print "Retrying the patch with RCS keywords cleaned up"
|
||||
if os.system(tryPatchCmd) == 0:
|
||||
patch_succeeded = True
|
||||
|
||||
if not patch_succeeded:
|
||||
print "What do you want to do?"
|
||||
response = "x"
|
||||
while response != "s" and response != "a" and response != "w":
|
||||
@ -1585,15 +1686,12 @@ class P4Sync(Command, P4UserMap):
|
||||
|
||||
# Note that we do not try to de-mangle keywords on utf16 files,
|
||||
# even though in theory somebody may want that.
|
||||
if type_base in ("text", "unicode", "binary"):
|
||||
if "ko" in type_mods:
|
||||
text = ''.join(contents)
|
||||
text = re.sub(r'\$(Id|Header):[^$]*\$', r'$\1$', text)
|
||||
contents = [ text ]
|
||||
elif "k" in type_mods:
|
||||
text = ''.join(contents)
|
||||
text = re.sub(r'\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$]*\$', r'$\1$', text)
|
||||
contents = [ text ]
|
||||
pattern = p4_keywords_regexp_for_type(type_base, type_mods)
|
||||
if pattern:
|
||||
regexp = re.compile(pattern, re.VERBOSE)
|
||||
text = ''.join(contents)
|
||||
text = regexp.sub(r'$\1$', text)
|
||||
contents = [ text ]
|
||||
|
||||
self.gitStream.write("M %s inline %s\n" % (git_mode, relPath))
|
||||
|
||||
|
Reference in New Issue
Block a user