result.update(entry)
return result;
+def p4Where(depotPath):
+ if not depotPath.endswith("/"):
+ depotPath += "/"
+ output = p4Cmd("where %s..." % depotPath)
+ clientPath = ""
+ if "path" in output:
+ clientPath = output.get("path")
+ elif "data" in output:
+ data = output.get("data")
+ lastSpace = data.rfind(" ")
+ clientPath = data[lastSpace + 1:]
+
+ if clientPath.endswith("..."):
+ clientPath = clientPath[:-3]
+ return clientPath
+
def die(msg):
sys.stderr.write(msg + "\n")
sys.exit(1)
def currentGitBranch():
- return os.popen("git-name-rev HEAD").read().split(" ")[1][:-1]
+ 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"):
if os.system(cmd) != 0:
die("command failed: %s" % cmd)
+def extractLogMessageFromGitCommit(commit):
+ logMessage = ""
+ foundTitle = False
+ for log in os.popen("git cat-file commit %s" % commit).readlines():
+ if not foundTitle:
+ if len(log) == 1:
+ foundTitle = 1
+ continue
+
+ logMessage += log
+ return logMessage
+
+def extractDepotPathAndChangeFromGitLog(log):
+ values = {}
+ for line in log.split("\n"):
+ line = line.strip()
+ if line.startswith("[git-p4:") and line.endswith("]"):
+ line = line[8:-1].strip()
+ for assignment in line.split(":"):
+ variable = assignment.strip()
+ value = ""
+ equalPos = assignment.find("=")
+ if equalPos != -1:
+ variable = assignment[:equalPos].strip()
+ value = assignment[equalPos + 1:].strip()
+ if value.startswith("\"") and value.endswith("\""):
+ value = value[1:-1]
+ values[variable] = value
+
+ return values.get("depot-path"), values.get("change")
+
+def gitBranchExists(branch):
+ if os.system("git rev-parse %s 2>/dev/null >/dev/null" % branch) == 0:
+ return True
+ return False
+
class Command:
def __init__(self):
self.usage = "usage: %prog [options]"
+ self.needsGit = True
class P4Debug(Command):
def __init__(self):
+ Command.__init__(self)
self.options = [
]
self.description = "A tool to debug the output of p4 -G."
+ self.needsGit = False
def run(self, args):
for output in p4CmdList(" ".join(args)):
def run(self, args):
branch = currentGitBranch()
print "Cleaning out stale p4 import tags..."
- sout, sin, serr = popen2.popen3("git-name-rev --tags `git-rev-parse %s`" % branch)
+ sout, sin, serr = popen2.popen3("git name-rev --tags `git rev-parse %s`" % branch)
output = sout.read()
try:
tagIdx = output.index(" tags/p4/")
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"),
optparse.make_option("--apply-as-patch", action="store_true", dest="applyAsPatch")
]
self.description = "Submit changes from git to the perforce depot."
+ self.usage += " [name of git branch to submit into 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.origin = ""
self.applyAsPatch = True
self.logSubstitutions = {}
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():
+ for line in os.popen("git rev-list --no-merges %s..%s" % (self.origin, self.master)).readlines():
commits.append(line[:-1])
commits.reverse()
return result
def apply(self, id):
- print "Applying %s" % (os.popen("git-log --max-count=1 --pretty=oneline %s" % id).read())
+ 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()
die("unknown modifier %s for %s" % (modifier, path))
if self.applyAsPatch:
- system("git-diff-tree -p --diff-filter=ACMRTUXB \"%s^\" \"%s\" | patch -p1" % (id, id))
+ system("git diff-tree -p --diff-filter=ACMRTUXB \"%s^\" \"%s\" | patch -p1" % (id, id))
else:
- system("git-diff-files --name-only -z | git-update-index --remove -z --stdin")
+ 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 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
+ logMessage = extractLogMessageFromGitCommit(id)
+ logMessage = logMessage.replace("\n", "\n\t")
+ logMessage = logMessage[:-1]
template = os.popen("p4 change -o").read()
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):
+ global gitdir
+ # make gitdir absolute so we can cd out into the perforce checkout
+ gitdir = os.path.abspath(gitdir)
+ os.environ["GIT_DIR"] = gitdir
+
+ if len(args) == 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!")
+ elif len(args) == 1:
+ self.master = args[0]
+ else:
+ return False
+
+ depotPath = ""
+ if gitBranchExists("p4"):
+ [depotPath, dummy] = extractDepotPathAndChangeFromGitLog(extractLogMessageFromGitCommit("p4"))
+ if len(depotPath) == 0 and gitBranchExists("origin"):
+ [depotPath, dummy] = extractDepotPathAndChangeFromGitLog(extractLogMessageFromGitCommit("origin"))
+
+ if len(depotPath) == 0:
+ print "Internal error: cannot locate perforce depot path from existing branches"
+ sys.exit(128)
+
+ clientPath = p4Where(depotPath)
+
+ if len(clientPath) == 0:
+ print "Error: Cannot locate perforce checkout of %s in client view" % depotPath
+ sys.exit(128)
+
+ print "Perforce checkout for depot path %s located at %s" % (depotPath, clientPath)
+ os.chdir(clientPath)
+ response = raw_input("Do you want to sync %s with p4 sync? (y/n) " % clientPath)
+ if response == "y" or response == "yes":
+ system("p4 sync ...")
+
+ if len(self.origin) == 0:
+ if gitBranchExists("p4"):
+ self.origin = "p4"
+ else:
+ self.origin = "origin"
+
if self.reset:
self.firstTime = True
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)
optparse.make_option("--changesfile", dest="changesFile"),
optparse.make_option("--silent", dest="silent", action="store_true"),
optparse.make_option("--known-branches", dest="knownBranches"),
- optparse.make_option("--cache", dest="doCache", action="store_true"),
+ optparse.make_option("--data-cache", dest="dataCache", action="store_true"),
optparse.make_option("--command-cache", dest="commandCache", action="store_true")
]
self.description = """Imports from Perforce into a git repository.\n
self.knownBranches = Set()
self.createdBranches = Set()
self.committedChanges = Set()
- self.branch = "p4"
+ self.branch = ""
self.detectBranches = False
self.changesFile = ""
if knownBranch:
continue
- for branch in knownBranches:
+ for branch in self.knownBranches:
#if relativePath.startswith(branch):
if self.isSubPathOf(relativePath, branch):
if len(branches) == 0:
self.gitStream.write("data <<EOT\n")
self.gitStream.write(details["desc"])
- self.gitStream.write("\n[git-p4: depot-path: \"%s\"; change: %s]\n" % (branchPrefix, details["change"]))
+ self.gitStream.write("\n[git-p4: depot-path = \"%s\": change = %s]\n" % (branchPrefix, details["change"]))
self.gitStream.write("EOT\n\n")
if len(parent) > 0:
self.gitStream.write("\n")
- self.lastChange = int(details["change"])
+ change = int(details["change"])
+
+ self.lastChange = change
+
+ if change in self.labels:
+ label = self.labels[change]
+ labelDetails = label[0]
+ labelRevisions = label[1]
+
+ files = p4CmdList("files %s...@%s" % (branchPrefix, change))
+
+ if len(files) == len(labelRevisions):
+
+ cleanedFiles = {}
+ for info in files:
+ if info["action"] == "delete":
+ continue
+ cleanedFiles[info["depotFile"]] = info["rev"]
+
+ if cleanedFiles == labelRevisions:
+ self.gitStream.write("tag tag_%s\n" % labelDetails["label"])
+ self.gitStream.write("from %s\n" % branch)
+
+ owner = labelDetails["Owner"]
+ tagger = ""
+ if author in self.users:
+ tagger = "%s %s %s" % (self.users[owner], epoch, self.tz)
+ else:
+ tagger = "%s <a@b> %s %s" % (owner, epoch, self.tz)
+ self.gitStream.write("tagger %s\n" % tagger)
+ self.gitStream.write("data <<EOT\n")
+ self.gitStream.write(labelDetails["Description"])
+ self.gitStream.write("EOT\n\n")
+
+ else:
+ if not self.silent:
+ print "Tag %s does not match with change %s: files do not match." % (labelDetails["label"], change)
+
+ else:
+ if not self.silent:
+ print "Tag %s does not match with change %s: file count is different." % (labelDetails["label"], change)
def extractFilesInCommitToBranch(self, files, branchPrefix):
newFiles = []
continue
self.users[output["User"]] = output["FullName"] + " <" + output["Email"] + ">"
+ def getLabels(self):
+ self.labels = {}
+
+ for output in p4CmdList("labels %s..." % self.globalPrefix):
+ label = output["label"]
+ revisions = {}
+ newestChange = 0
+ for file in p4CmdList("files //...@%s" % label):
+ revisions[file["depotFile"]] = file["rev"]
+ change = int(file["change"])
+ if change > newestChange:
+ newestChange = change
+
+ self.labels[newestChange] = [output, revisions]
+
def run(self, args):
+ self.globalPrefix = ""
+ self.changeRange = ""
+ self.initialParent = ""
+ self.tagLastChange = True
+
+ if len(self.branch) == 0:
+ self.branch = "p4"
+
+ if len(args) == 0:
+ if not gitBranchExists(self.branch) and gitBranchExists("origin"):
+ if not self.silent:
+ print "Creating %s branch in git repository based on origin" % self.branch
+ system("git branch %s origin" % self.branch)
+
+ [self.previousDepotPath, p4Change] = extractDepotPathAndChangeFromGitLog(extractLogMessageFromGitCommit(self.branch))
+ if len(self.previousDepotPath) > 0 and len(p4Change) > 0:
+ p4Change = int(p4Change) + 1
+ self.globalPrefix = self.previousDepotPath
+ self.changeRange = "@%s,#head" % p4Change
+ self.initialParent = self.branch
+ self.tagLastChange = False
+ if not self.silent:
+ print "Performing incremental import into %s git branch" % self.branch
+
self.branch = "refs/heads/" + self.branch
- self.globalPrefix = self.previousDepotPath = os.popen("git-repo-config --get p4.depotpath").read()
+
+ if len(self.globalPrefix) == 0:
+ self.globalPrefix = self.previousDepotPath = os.popen("git repo-config --get p4.depotpath").read()
+
if len(self.globalPrefix) != 0:
self.globalPrefix = self.globalPrefix[:-1]
if len(args) == 0 and len(self.globalPrefix) != 0:
if not self.silent:
- print "[using previously specified depot path %s]" % self.globalPrefix
+ print "Depot path: %s" % self.globalPrefix
elif len(args) != 1:
return False
else:
sys.exit(1)
self.globalPrefix = args[0]
- self.changeRange = ""
self.revision = ""
self.users = {}
- self.initialParent = ""
self.lastChange = 0
self.initialTag = ""
self.globalPrefix += "/"
self.getUserMap()
+ self.getLabels();
if len(self.changeRange) == 0:
try:
- sout, sin, serr = popen2.popen3("git-name-rev --tags `git-rev-parse %s`" % self.branch)
+ sout, sin, serr = popen2.popen3("git name-rev --tags `git rev-parse %s`" % self.branch)
output = sout.read()
if output.endswith("\n"):
output = output[:-1]
endPos = caretIdx
self.rev = int(output[tagIdx + 9 : endPos]) + 1
self.changeRange = "@%s,#head" % self.rev
- self.initialParent = os.popen("git-rev-parse %s" % self.branch).read()[:-1]
+ self.initialParent = os.popen("git rev-parse %s" % self.branch).read()[:-1]
self.initialTag = "p4/%s" % (int(self.rev) - 1)
except:
pass
if tzsign != '+' and tzsign != '-':
self.tz = "+" + ("%s" % self.tz)
- self.gitOutput, self.gitStream, self.gitError = popen2.popen3("git-fast-import")
+ self.gitOutput, self.gitStream, self.gitError = popen2.popen3("git fast-import")
if len(self.revision) > 0:
print "Doing initial import of %s from revision %s" % (self.globalPrefix, self.revision)
if not self.silent:
print ""
- self.gitStream.write("reset refs/tags/p4/%s\n" % self.lastChange)
- self.gitStream.write("from %s\n\n" % self.branch);
+ if self.tagLastChange:
+ self.gitStream.write("reset refs/tags/p4/%s\n" % self.lastChange)
+ self.gitStream.write("from %s\n\n" % self.branch);
self.gitStream.close()
self.gitOutput.close()
self.gitError.close()
- os.popen("git-repo-config p4.depotpath %s" % self.globalPrefix).read()
+ os.popen("git repo-config p4.depotpath %s" % self.globalPrefix).read()
if len(self.initialTag) > 0:
os.popen("git tag -d %s" % self.initialTag).read()
options = cmd.options
cmd.gitdir = gitdir
-options.append(optparse.make_option("--git-dir", dest="gitdir"))
-parser = optparse.OptionParser(cmd.usage.replace("%prog", "%prog " + cmdName),
- options,
- description = cmd.description,
- formatter = HelpFormatter())
+args = sys.argv[2:]
-(cmd, args) = parser.parse_args(sys.argv[2:], cmd);
+if len(options) > 0:
+ options.append(optparse.make_option("--git-dir", dest="gitdir"))
-gitdir = cmd.gitdir
-if len(gitdir) == 0:
- gitdir = ".git"
- if not isValidGitDir(gitdir):
- cdup = os.popen("git-rev-parse --show-cdup").read()[:-1]
- if isValidGitDir(cdup + "/" + gitdir):
- os.chdir(cdup)
+ parser = optparse.OptionParser(cmd.usage.replace("%prog", "%prog " + cmdName),
+ options,
+ description = cmd.description,
+ formatter = HelpFormatter())
+
+ (cmd, args) = parser.parse_args(sys.argv[2:], cmd);
-if not isValidGitDir(gitdir):
- if isValidGitDir(gitdir + "/.git"):
- gitdir += "/.git"
- else:
- die("fatal: cannot locate git repository at %s" % gitdir)
+if cmd.needsGit:
+ gitdir = cmd.gitdir
+ if len(gitdir) == 0:
+ gitdir = ".git"
+ if not isValidGitDir(gitdir):
+ cdup = os.popen("git rev-parse --show-cdup").read()[:-1]
+ if isValidGitDir(cdup + "/" + gitdir):
+ os.chdir(cdup)
+
+ if not isValidGitDir(gitdir):
+ if isValidGitDir(gitdir + "/.git"):
+ gitdir += "/.git"
+ else:
+ die("fatal: cannot locate git repository at %s" % gitdir)
-os.environ["GIT_DIR"] = gitdir
+ os.environ["GIT_DIR"] = gitdir
if not cmd.run(args):
parser.print_help()