First (untested) attempt at migrating p4-git-sync into the final git-p4 script

Signed-off-by: Simon Hausmann <hausmann@kde.org>
This commit is contained in:
Simon Hausmann 2007-03-19 22:25:17 +01:00
parent c8c3911685
commit 4f5cf76a55

View File

@ -6,7 +6,10 @@
# License: MIT <http://www.opensource.org/licenses/mit-license.php>
#
import optparse, sys, os, marshal, popen2
import optparse, sys, os, marshal, popen2, shelve
import tempfile
gitdir = os.environ.get("GIT_DIR", "")
def p4CmdList(cmd):
cmd = "p4 -G %s" % cmd
@ -37,6 +40,15 @@ def die(msg):
def currentGitBranch():
return os.popen("git-name-rev HEAD").read().split(" ")[1][:-1]
def isValidGitDir(path):
if os.path.exists(path + "/HEAD") and os.path.exists(path + "/refs") and os.path.exists(path + "/objects"):
return True;
return False
def system(cmd):
if os.system(cmd) != 0:
die("command failed: %s" % cmd)
class P4Debug:
def __init__(self):
self.options = [
@ -83,6 +95,214 @@ class P4CleanTags:
print "%s tags removed." % len(allTags)
class P4Sync:
def __init__(self):
self.options = [
optparse.make_option("--continue", action="store_false", dest="firstTime"),
optparse.make_option("--origin", dest="origin"),
optparse.make_option("--reset", action="store_true", dest="reset"),
optparse.make_option("--master", dest="master"),
optparse.make_option("--log-substitutions", dest="substFile"),
optparse.make_option("--noninteractive", action="store_false"),
optparse.make_option("--dry-run", action="store_true")
]
self.description = "Submit changes from git to the perforce depot."
self.firstTime = True
self.reset = False
self.interactive = True
self.dryRun = False
self.substFile = ""
self.firstTime = True
self.origin = "origin"
self.master = ""
self.logSubstitutions = {}
self.logSubstitutions["<enter description here>"] = "%log%"
self.logSubstitutions["\tDetails:"] = "\tDetails: %log%"
def check(self):
if len(p4CmdList("opened ...")) > 0:
die("You have files opened with perforce! Close them before starting the sync.")
def start(self):
if len(self.config) > 0 and not self.reset:
die("Cannot start sync. Previous sync config found at %s" % self.configFile)
commits = []
for line in os.popen("git-rev-list --no-merges %s..%s" % (self.origin, self.master)).readlines():
commits.append(line[:-1])
commits.reverse()
self.config["commits"] = commits
print "Creating temporary p4-sync branch from %s ..." % self.origin
system("git checkout -f -b p4-sync %s" % self.origin)
def prepareLogMessage(self, template, message):
result = ""
for line in template.split("\n"):
if line.startswith("#"):
result += line + "\n"
continue
substituted = False
for key in self.logSubstitutions.keys():
if line.find(key) != -1:
value = self.logSubstitutions[key]
value = value.replace("%log%", message)
if value != "@remove@":
result += line.replace(key, value) + "\n"
substituted = True
break
if not substituted:
result += line + "\n"
return result
def apply(self, id):
print "Applying %s" % (os.popen("git-log --max-count=1 --pretty=oneline %s" % id).read())
diff = os.popen("git diff-tree -r --name-status \"%s^\" \"%s\"" % (id, id)).readlines()
filesToAdd = set()
filesToDelete = set()
for line in diff:
modifier = line[0]
path = line[1:].strip()
if modifier == "M":
system("p4 edit %s" % path)
elif modifier == "A":
filesToAdd.add(path)
if path in filesToDelete:
filesToDelete.remove(path)
elif modifier == "D":
filesToDelete.add(path)
if path in filesToAdd:
filesToAdd.remove(path)
else:
die("unknown modifier %s for %s" % (modifier, path))
system("git-diff-files --name-only -z | git-update-index --remove -z --stdin")
system("git cherry-pick --no-commit \"%s\"" % id)
for f in filesToAdd:
system("p4 add %s" % f)
for f in filesToDelete:
system("p4 revert %s" % f)
system("p4 delete %s" % f)
logMessage = ""
foundTitle = False
for log in os.popen("git-cat-file commit %s" % id).readlines():
if not foundTitle:
if len(log) == 1:
foundTitle = 1
continue
if len(logMessage) > 0:
logMessage += "\t"
logMessage += log
template = os.popen("p4 change -o").read()
if self.interactive:
submitTemplate = self.prepareLogMessage(template, logMessage)
diff = os.popen("p4 diff -du ...").read()
for newFile in filesToAdd:
diff += "==== new file ====\n"
diff += "--- /dev/null\n"
diff += "+++ %s\n" % newFile
f = open(newFile, "r")
for line in f.readlines():
diff += "+" + line
f.close()
pipe = os.popen("less", "w")
pipe.write(submitTemplate + diff)
pipe.close()
response = "e"
while response == "e":
response = raw_input("Do you want to submit this change (y/e/n)? ")
if response == "e":
[handle, fileName] = tempfile.mkstemp()
tmpFile = os.fdopen(handle, "w+")
tmpFile.write(submitTemplate)
tmpFile.close()
editor = os.environ.get("EDITOR", "vi")
system(editor + " " + fileName)
tmpFile = open(fileName, "r")
submitTemplate = tmpFile.read()
tmpFile.close()
os.remove(fileName)
if response == "y" or response == "yes":
if self.dryRun:
print submitTemplate
raw_input("Press return to continue...")
else:
pipe = os.popen("p4 submit -i", "w")
pipe.write(submitTemplate)
pipe.close()
else:
print "Not submitting!"
self.interactive = False
else:
fileName = "submit.txt"
file = open(fileName, "w+")
file.write(self.prepareLogMessage(template, logMessage))
file.close()
print "Perforce submit template written as %s. Please review/edit and then use p4 submit -i < %s to submit directly!" % (fileName, fileName)
def run(self, args):
if self.reset:
self.firstTime = True
if len(self.substFile) > 0:
for line in open(self.substFile, "r").readlines():
tokens = line[:-1].split("=")
self.logSubstitutions[tokens[0]] = tokens[1]
if len(self.master) == 0:
self.master = currentGitBranch()
if len(self.master) == 0 or not os.path.exists("%s/refs/heads/%s" % (gitdir, self.master)):
die("Detecting current git branch failed!")
self.check()
self.configFile = gitdir + "/p4-git-sync.cfg"
self.config = shelve.open(self.configFile, writeback=True)
if self.firstTime:
self.start()
commits = self.config.get("commits", [])
while len(commits) > 0:
self.firstTime = False
commit = commits[0]
commits = commits[1:]
self.config["commits"] = commits
self.apply(commit)
if not self.interactive:
break
self.config.close()
if len(commits) == 0:
if self.firstTime:
print "No changes found to apply between %s and current HEAD" % self.origin
else:
print "All changes applied!"
print "Deleting temporary p4-sync branch and going back to %s" % self.master
system("git checkout %s" % self.master)
system("git branch -D p4-sync")
print "Cleaning out your perforce checkout by doing p4 edit ... ; p4 revert ..."
system("p4 edit ... >/dev/null")
system("p4 revert ... >/dev/null")
os.remove(self.configFile)
def printUsage(commands):
print "usage: %s <command> [options]" % sys.argv[0]
print ""
@ -93,7 +313,8 @@ def printUsage(commands):
commands = {
"debug" : P4Debug(),
"clean-tags" : P4CleanTags()
"clean-tags" : P4CleanTags(),
"sync-to-perforce" : P4Sync()
}
if len(sys.argv[1:]) == 0:
@ -110,9 +331,25 @@ except KeyError:
printUsage(commands.keys())
sys.exit(2)
parser = optparse.OptionParser("usage: %prog " + cmdName + " [options]", cmd.options,
options = cmd.options
cmd.gitdir = gitdir
options.append(optparse.make_option("--git-dir", dest="gitdir"))
parser = optparse.OptionParser("usage: %prog " + cmdName + " [options]", options,
description = cmd.description)
(cmd, args) = parser.parse_args(sys.argv[2:], cmd);
gitdir = cmd.gitdir
if len(gitdir) == 0:
gitdir = ".git"
if not isValidGitDir(gitdir):
if isValidGitDir(gitdir + "/.git"):
gitdir += "/.git"
else:
dir("fatal: cannot locate git repository at %s" % gitdir)
os.environ["GIT_DIR"] = gitdir
cmd.run(args)