in git-p4.py [0:0]
def applyCommit(self, id):
"""Apply one commit, return True if it succeeded."""
print("Applying", read_pipe(["git", "show", "-s",
"--format=format:%h %s", id]))
p4User, gitEmail = self.p4UserForCommit(id)
diff = read_pipe_lines(
["git", "diff-tree", "-r"] + self.diffOpts + ["{}^".format(id), id])
filesToAdd = set()
filesToChangeType = set()
filesToDelete = set()
editedFiles = set()
pureRenameCopy = set()
symlinks = set()
filesToChangeExecBit = {}
all_files = list()
for line in diff:
diff = parseDiffTreeEntry(line)
modifier = diff['status']
path = diff['src']
all_files.append(path)
if modifier == "M":
p4_edit(path)
if isModeExecChanged(diff['src_mode'], diff['dst_mode']):
filesToChangeExecBit[path] = diff['dst_mode']
editedFiles.add(path)
elif modifier == "A":
filesToAdd.add(path)
filesToChangeExecBit[path] = diff['dst_mode']
if path in filesToDelete:
filesToDelete.remove(path)
dst_mode = int(diff['dst_mode'], 8)
if dst_mode == 0o120000:
symlinks.add(path)
elif modifier == "D":
filesToDelete.add(path)
if path in filesToAdd:
filesToAdd.remove(path)
elif modifier == "C":
src, dest = diff['src'], diff['dst']
all_files.append(dest)
p4_integrate(src, dest)
pureRenameCopy.add(dest)
if diff['src_sha1'] != diff['dst_sha1']:
p4_edit(dest)
pureRenameCopy.discard(dest)
if isModeExecChanged(diff['src_mode'], diff['dst_mode']):
p4_edit(dest)
pureRenameCopy.discard(dest)
filesToChangeExecBit[dest] = diff['dst_mode']
if self.isWindows:
# turn off read-only attribute
os.chmod(dest, stat.S_IWRITE)
os.unlink(dest)
editedFiles.add(dest)
elif modifier == "R":
src, dest = diff['src'], diff['dst']
all_files.append(dest)
if self.p4HasMoveCommand:
p4_edit(src) # src must be open before move
p4_move(src, dest) # opens for (move/delete, move/add)
else:
p4_integrate(src, dest)
if diff['src_sha1'] != diff['dst_sha1']:
p4_edit(dest)
else:
pureRenameCopy.add(dest)
if isModeExecChanged(diff['src_mode'], diff['dst_mode']):
if not self.p4HasMoveCommand:
p4_edit(dest) # with move: already open, writable
filesToChangeExecBit[dest] = diff['dst_mode']
if not self.p4HasMoveCommand:
if self.isWindows:
os.chmod(dest, stat.S_IWRITE)
os.unlink(dest)
filesToDelete.add(src)
editedFiles.add(dest)
elif modifier == "T":
filesToChangeType.add(path)
else:
die("unknown modifier %s for %s" % (modifier, path))
diffcmd = "git diff-tree --full-index -p \"%s\"" % (id)
patchcmd = diffcmd + " | git apply "
tryPatchCmd = patchcmd + "--check -"
applyPatchCmd = patchcmd + "--check --apply -"
patch_succeeded = True
if verbose:
print("TryPatch: %s" % tryPatchCmd)
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 gitConfigBool("git-p4.attemptRCSCleanup"):
file = None
kwfiles = {}
for file in editedFiles | filesToDelete:
# did this file's delta contain RCS keywords?
regexp = p4_keywords_regexp_for_file(file)
if regexp:
# this file is a possibility...look for RCS keywords.
for line in read_pipe_lines(
["git", "diff", "%s^..%s" % (id, id), file],
raw=True):
if regexp.search(line):
if verbose:
print("got keyword match on %s in %s in %s" % (regexp.pattern, line, file))
kwfiles[file] = regexp
break
for file, regexp in kwfiles.items():
if verbose:
print("zapping %s with %s" % (line, regexp.pattern))
# File is being deleted, so not open in p4. Must
# disable the read-only bit on windows.
if self.isWindows and file not in editedFiles:
os.chmod(file, stat.S_IWRITE)
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
print("Patch succeesed this time with RCS keywords cleaned")
if not patch_succeeded:
for f in editedFiles:
p4_revert(f)
return False
#
# Apply the patch for real, and do add/delete/+x handling.
#
system(applyPatchCmd, shell=True)
for f in filesToChangeType:
p4_edit(f, "-t", "auto")
for f in filesToAdd:
p4_add(f)
for f in filesToDelete:
p4_revert(f)
p4_delete(f)
# Set/clear executable bits
for f in filesToChangeExecBit.keys():
mode = filesToChangeExecBit[f]
setP4ExecBit(f, mode)
update_shelve = 0
if len(self.update_shelve) > 0:
update_shelve = self.update_shelve.pop(0)
p4_reopen_in_change(update_shelve, all_files)
#
# Build p4 change description, starting with the contents
# of the git commit message.
#
logMessage = extractLogMessageFromGitCommit(id)
logMessage = logMessage.strip()
logMessage, jobs = self.separate_jobs_from_description(logMessage)
template = self.prepareSubmitTemplate(update_shelve)
submitTemplate = self.prepareLogMessage(template, logMessage, jobs)
if self.preserveUser:
submitTemplate += "\n######## Actual user %s, modified after commit\n" % p4User
if self.checkAuthorship and not self.p4UserIsMe(p4User):
submitTemplate += "######## git author %s does not match your p4 account.\n" % gitEmail
submitTemplate += "######## Use option --preserve-user to modify authorship.\n"
submitTemplate += "######## Variable git-p4.skipUserNameCheck hides this message.\n"
separatorLine = "######## everything below this line is just the diff #######\n"
if not self.prepare_p4_only:
submitTemplate += separatorLine
submitTemplate += self.get_diff_description(editedFiles, filesToAdd, symlinks)
handle, fileName = tempfile.mkstemp()
tmpFile = os.fdopen(handle, "w+b")
if self.isWindows:
submitTemplate = submitTemplate.replace("\n", "\r\n")
tmpFile.write(encode_text_stream(submitTemplate))
tmpFile.close()
submitted = False
try:
# Allow the hook to edit the changelist text before presenting it
# to the user.
if not run_git_hook("p4-prepare-changelist", [fileName]):
return False
if self.prepare_p4_only:
#
# Leave the p4 tree prepared, and the submit template around
# and let the user decide what to do next
#
submitted = True
print("")
print("P4 workspace prepared for submission.")
print("To submit or revert, go to client workspace")
print(" " + self.clientPath)
print("")
print("To submit, use \"p4 submit\" to write a new description,")
print("or \"p4 submit -i <%s\" to use the one prepared by"
" \"git p4\"." % fileName)
print("You can delete the file \"%s\" when finished." % fileName)
if self.preserveUser and p4User and not self.p4UserIsMe(p4User):
print("To preserve change ownership by user %s, you must\n"
"do \"p4 change -f <change>\" after submitting and\n"
"edit the User field.")
if pureRenameCopy:
print("After submitting, renamed files must be re-synced.")
print("Invoke \"p4 sync -f\" on each of these files:")
for f in pureRenameCopy:
print(" " + f)
print("")
print("To revert the changes, use \"p4 revert ...\", and delete")
print("the submit template file \"%s\"" % fileName)
if filesToAdd:
print("Since the commit adds new files, they must be deleted:")
for f in filesToAdd:
print(" " + f)
print("")
sys.stdout.flush()
return True
if self.edit_template(fileName):
if not self.no_verify:
if not run_git_hook("p4-changelist", [fileName]):
print("The p4-changelist hook failed.")
sys.stdout.flush()
return False
# read the edited message and submit
tmpFile = open(fileName, "rb")
message = decode_text_stream(tmpFile.read())
tmpFile.close()
if self.isWindows:
message = message.replace("\r\n", "\n")
if message.find(separatorLine) != -1:
submitTemplate = message[:message.index(separatorLine)]
else:
submitTemplate = message
if len(submitTemplate.strip()) == 0:
print("Changelist is empty, aborting this changelist.")
sys.stdout.flush()
return False
if update_shelve:
p4_write_pipe(['shelve', '-r', '-i'], submitTemplate)
elif self.shelve:
p4_write_pipe(['shelve', '-i'], submitTemplate)
else:
p4_write_pipe(['submit', '-i'], submitTemplate)
# The rename/copy happened by applying a patch that created a
# new file. This leaves it writable, which confuses p4.
for f in pureRenameCopy:
p4_sync(f, "-f")
if self.preserveUser:
if p4User:
# Get last changelist number. Cannot easily get it from
# the submit command output as the output is
# unmarshalled.
changelist = self.lastP4Changelist()
self.modifyChangelistUser(changelist, p4User)
submitted = True
run_git_hook("p4-post-changelist")
finally:
# Revert changes if we skip this patch
if not submitted or self.shelve:
if self.shelve:
print("Reverting shelved files.")
else:
print("Submission cancelled, undoing p4 changes.")
sys.stdout.flush()
for f in editedFiles | filesToDelete:
p4_revert(f)
for f in filesToAdd:
p4_revert(f)
os.remove(f)
if not self.prepare_p4_only:
os.remove(fileName)
return submitted