From 0bcff6121d68d8733e9b572eba357bcd8e91e23e Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 12 Mar 2007 23:00:34 +0100 Subject: [PATCH] First version of a new script to submit changes back to perforce from git repositories. Signed-off-by: Simon Hausmann --- contrib/fast-import/p4-git-sync.py | 208 +++++++++++++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100755 contrib/fast-import/p4-git-sync.py diff --git a/contrib/fast-import/p4-git-sync.py b/contrib/fast-import/p4-git-sync.py new file mode 100755 index 000000000..8982e4534 --- /dev/null +++ b/contrib/fast-import/p4-git-sync.py @@ -0,0 +1,208 @@ +#!/usr/bin/python +# +# p4-git-sync.py +# +# Author: Simon Hausmann +# License: MIT +# + +import os, string, shelve, stat +import getopt, sys, marshal + +def p4CmdList(cmd): + cmd = "p4 -G %s" % cmd + pipe = os.popen(cmd, "rb") + + result = [] + try: + while True: + entry = marshal.load(pipe) + result.append(entry) + except EOFError: + pass + pipe.close() + + return result + +def p4Cmd(cmd): + list = p4CmdList(cmd) + result = {} + for entry in list: + result.update(entry) + return result; + +try: + opts, args = getopt.getopt(sys.argv[1:], "", [ "continue", "--git-dir=", "origin=", "reset", "master=", + "submit-log-subst=" ]) +except getopt.GetoptError: + print "fixme, syntax error" + sys.exit(1) + +logSubstitutions = {} +logSubstitutions[""] = "%log%" +logSubstitutions["\tDetails:"] = "\tDetails: %log%" +gitdir = os.environ.get("GIT_DIR", "") +origin = "origin" +master = "master" +firstTime = True +reset = False + +for o, a in opts: + if o == "--git-dir": + gitdir = a + elif o == "--origin": + origin = a + elif o == "--master": + master = a + elif o == "--continue": + firstTime = False + elif o == "--reset": + reset = True + firstTime = True + elif o == "--submit-log-subst": + key = a.split("%")[0] + value = a.split("%")[1] + logSubstitutions[key] = value + +if len(gitdir) == 0: + gitdir = ".git" +else: + os.environ["GIT_DIR"] = gitdir + +configFile = gitdir + "/p4-git-sync.cfg" + +origin = "origin" +if len(args) == 1: + origin = args[0] + +def die(msg): + sys.stderr.write(msg + "\n") + sys.exit(1) + +def system(cmd): + if os.system(cmd) != 0: + die("command failed: %s" % cmd) + +def check(): + return + if len(p4CmdList("opened ...")) > 0: + die("You have files opened with perforce! Close them before starting the sync.") + +def start(config): + if len(config) > 0 and not reset: + die("Cannot start sync. Previous sync config found at %s" % configFile) + + #if len(os.popen("git-update-index --refresh").read()) > 0: + # die("Your working tree is not clean. Check with git status!") + + commits = [] + for line in os.popen("git-rev-list --no-merges %s..%s" % (origin, master)).readlines(): + commits.append(line[:-1]) + commits.reverse() + + config["commits"] = commits + +# print "Cleaning index..." +# system("git checkout -f") + +def prepareLogMessage(template, message): + result = "" + + substs = logSubstitutions + for k in substs.keys(): + substs[k] = substs[k].replace("%log%", message) + + for line in template.split("\n"): + if line.startswith("#"): + result += line + "\n" + continue + + substituted = False + for key in substs.keys(): + if line.find(key) != -1: + value = substs[key] + if value != "@remove@": + result += line.replace(key, value) + "\n" + substituted = True + break + + if not substituted: + result += line + "\n" + + return result + +def apply(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(): + log = log[:-1] + if not foundTitle: + if len(log) == 0: + foundTitle = 1 + continue + + if len(logMessage) > 0: + logMessage += "\t" + logMessage += log + "\n" + + template = os.popen("p4 change -o").read() + fileName = "submit.txt" + file = open(fileName, "w+") + file.write(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) + +check() + +config = shelve.open(configFile, writeback=True) + +if firstTime: + start(config) + +commits = config.get("commits", []) + +if len(commits) > 0: + firstTime = False + commit = commits[0] + commits = commits[1:] + config["commits"] = commits + apply(commit) + +config.close() + +if len(commits) == 0: + if firstTime: + print "No changes found to apply between %s and current HEAD" % origin + else: + print "All changes applied!" + os.remove(configFile) + -- 2.26.2