Browse Source

Started rewriting the branch detection, based on "p4 branches" and "p4 branch -o foo".

Signed-off-by: Simon Hausmann <shausman@trolltech.com>
maint
Simon Hausmann 18 years ago
parent
commit
4b97ffb1e4
  1. 287
      contrib/fast-import/git-p4

287
contrib/fast-import/git-p4

@ -414,9 +414,9 @@ class P4Sync(Command): @@ -414,9 +414,9 @@ class P4Sync(Command):
optparse.make_option("--detect-branches", dest="detectBranches", action="store_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("--detect-labels", dest="detectLabels", action="store_true"),
optparse.make_option("--with-origin", dest="syncWithOrigin", action="store_true")
optparse.make_option("--with-origin", dest="syncWithOrigin", action="store_true"),
optparse.make_option("--verbose", dest="verbose", action="store_true")
]
self.description = """Imports from Perforce into a git repository.\n
example:
@ -429,7 +429,6 @@ class P4Sync(Command): @@ -429,7 +429,6 @@ class P4Sync(Command):
self.usage += " //depot/path[@revRange]"

self.silent = False
self.knownBranches = Set()
self.createdBranches = Set()
self.committedChanges = Set()
self.branch = ""
@ -437,6 +436,7 @@ class P4Sync(Command): @@ -437,6 +436,7 @@ class P4Sync(Command):
self.detectLabels = False
self.changesFile = ""
self.syncWithOrigin = False
self.verbose = False

def p4File(self, depotPath):
return os.popen("p4 print -q \"%s\"" % depotPath, "rb").read()
@ -461,120 +461,25 @@ class P4Sync(Command): @@ -461,120 +461,25 @@ class P4Sync(Command):
fnum = fnum + 1
return files

def isSubPathOf(self, first, second):
if not first.startswith(second):
return False
if first == second:
return True
return first[len(second)] == "/"

def branchesForCommit(self, files):
branches = Set()

for file in files:
relativePath = file["path"][len(self.depotPath):]
# strip off the filename
relativePath = relativePath[0:relativePath.rfind("/")]

# if len(branches) == 0:
# branches.add(relativePath)
# knownBranches.add(relativePath)
# continue

###### this needs more testing :)
knownBranch = False
for branch in branches:
if relativePath == branch:
knownBranch = True
break
# if relativePath.startswith(branch):
if self.isSubPathOf(relativePath, branch):
knownBranch = True
break
# if branch.startswith(relativePath):
if self.isSubPathOf(branch, relativePath):
branches.remove(branch)
break

if knownBranch:
continue

for branch in self.knownBranches:
#if relativePath.startswith(branch):
if self.isSubPathOf(relativePath, branch):
if len(branches) == 0:
relativePath = branch
else:
knownBranch = True
break
path = file["path"][len(self.depotPath):]

if knownBranch:
continue

branches.add(relativePath)
self.knownBranches.add(relativePath)
for branch in self.knownBranches.keys():
if path.startswith(branch):
branches.add(branch)

return branches

def findBranchParent(self, branchPrefix, files):
for file in files:
path = file["path"]
if not path.startswith(branchPrefix):
continue
action = file["action"]
if action != "integrate" and action != "branch":
continue
rev = file["rev"]
depotPath = path + "#" + rev

log = p4CmdList("filelog \"%s\"" % depotPath)
if len(log) != 1:
print "eek! I got confused by the filelog of %s" % depotPath
sys.exit(1);

log = log[0]
if log["action0"] != action:
print "eek! wrong action in filelog for %s : found %s, expected %s" % (depotPath, log["action0"], action)
sys.exit(1);

branchAction = log["how0,0"]
# if branchAction == "branch into" or branchAction == "ignored":
# continue # ignore for branching

if not branchAction.endswith(" from"):
continue # ignore for branching
# print "eek! file %s was not branched from but instead: %s" % (depotPath, branchAction)
# sys.exit(1);

source = log["file0,0"]
if source.startswith(branchPrefix):
continue

lastSourceRev = log["erev0,0"]

sourceLog = p4CmdList("filelog -m 1 \"%s%s\"" % (source, lastSourceRev))
if len(sourceLog) != 1:
print "eek! I got confused by the source filelog of %s%s" % (source, lastSourceRev)
sys.exit(1);
sourceLog = sourceLog[0]

relPath = source[len(self.depotPath):]
# strip off the filename
relPath = relPath[0:relPath.rfind("/")]

for branch in self.knownBranches:
if self.isSubPathOf(relPath, branch):
# print "determined parent branch branch %s due to change in file %s" % (branch, source)
return branch
# else:
# print "%s is not a subpath of branch %s" % (relPath, branch)

return ""

def commit(self, details, files, branch, branchPrefix, parent = "", merged = ""):
def commit(self, details, files, branch, branchPrefix, parent = ""):
epoch = details["time"]
author = details["user"]

if self.verbose:
print "commit into %s" % branch

self.gitStream.write("commit %s\n" % branch)
# gitStream.write("mark :%s\n" % details["change"])
self.committedChanges.add(int(details["change"]))
@ -592,11 +497,10 @@ class P4Sync(Command): @@ -592,11 +497,10 @@ class P4Sync(Command):
self.gitStream.write("EOT\n\n")

if len(parent) > 0:
if self.verbose:
print "parent %s" % parent
self.gitStream.write("from %s\n" % parent)

if len(merged) > 0:
self.gitStream.write("merge %s\n" % merged)

for file in files:
path = file["path"]
if not path.startswith(branchPrefix):
@ -680,118 +584,6 @@ class P4Sync(Command): @@ -680,118 +584,6 @@ class P4Sync(Command):

return newFiles

def findBranchSourceHeuristic(self, files, branch, branchPrefix):
for file in files:
action = file["action"]
if action != "integrate" and action != "branch":
continue
path = file["path"]
rev = file["rev"]
depotPath = path + "#" + rev

log = p4CmdList("filelog \"%s\"" % depotPath)
if len(log) != 1:
print "eek! I got confused by the filelog of %s" % depotPath
sys.exit(1);

log = log[0]
if log["action0"] != action:
print "eek! wrong action in filelog for %s : found %s, expected %s" % (depotPath, log["action0"], action)
sys.exit(1);

branchAction = log["how0,0"]

if not branchAction.endswith(" from"):
continue # ignore for branching
# print "eek! file %s was not branched from but instead: %s" % (depotPath, branchAction)
# sys.exit(1);

source = log["file0,0"]
if source.startswith(branchPrefix):
continue

lastSourceRev = log["erev0,0"]

sourceLog = p4CmdList("filelog -m 1 \"%s%s\"" % (source, lastSourceRev))
if len(sourceLog) != 1:
print "eek! I got confused by the source filelog of %s%s" % (source, lastSourceRev)
sys.exit(1);
sourceLog = sourceLog[0]

relPath = source[len(self.depotPath):]
# strip off the filename
relPath = relPath[0:relPath.rfind("/")]

for candidate in self.knownBranches:
if self.isSubPathOf(relPath, candidate) and candidate != branch:
return candidate

return ""

def changeIsBranchMerge(self, sourceBranch, destinationBranch, change):
sourceFiles = {}
for file in p4CmdList("files %s...@%s" % (self.depotPath + sourceBranch + "/", change)):
if file["action"] == "delete":
continue
sourceFiles[file["depotFile"]] = file

destinationFiles = {}
for file in p4CmdList("files %s...@%s" % (self.depotPath + destinationBranch + "/", change)):
destinationFiles[file["depotFile"]] = file

for fileName in sourceFiles.keys():
integrations = []
deleted = False
integrationCount = 0
for integration in p4CmdList("integrated \"%s\"" % fileName):
toFile = integration["fromFile"] # yes, it's true, it's fromFile
if not toFile in destinationFiles:
continue
destFile = destinationFiles[toFile]
if destFile["action"] == "delete":
# print "file %s has been deleted in %s" % (fileName, toFile)
deleted = True
break
integrationCount += 1
if integration["how"] == "branch from":
continue

if int(integration["change"]) == change:
integrations.append(integration)
continue
if int(integration["change"]) > change:
continue

destRev = int(destFile["rev"])

startRev = integration["startFromRev"][1:]
if startRev == "none":
startRev = 0
else:
startRev = int(startRev)

endRev = integration["endFromRev"][1:]
if endRev == "none":
endRev = 0
else:
endRev = int(endRev)

initialBranch = (destRev == 1 and integration["how"] != "branch into")
inRange = (destRev >= startRev and destRev <= endRev)
newer = (destRev > startRev and destRev > endRev)

if initialBranch or inRange or newer:
integrations.append(integration)

if deleted:
continue

if len(integrations) == 0 and integrationCount > 1:
print "file %s was not integrated from %s into %s" % (fileName, sourceBranch, destinationBranch)
return False

return True

def getUserMap(self):
self.users = {}

@ -819,6 +611,27 @@ class P4Sync(Command): @@ -819,6 +611,27 @@ class P4Sync(Command):

self.labels[newestChange] = [output, revisions]

def getBranchMapping(self):
# map from branch depot path to parent branch
self.knownBranches = {}

for info in p4CmdList("branches"):
details = p4Cmd("branch -o %s" % info["branch"])
viewIdx = 0
while details.has_key("View%s" % viewIdx):
paths = details["View%s" % viewIdx].split(" ")
viewIdx = viewIdx + 1
# require standard //depot/foo/... //depot/bar/... mapping
if len(paths) != 2 or not paths[0].endswith("/...") or not paths[1].endswith("/..."):
continue
source = paths[0]
destination = paths[1]
if source.startswith(self.depotPath) and destination.startswith(self.depotPath):
source = source[len(self.depotPath):-4]
destination = destination[len(self.depotPath):-4]
self.knownBranches[destination] = source
self.knownBranches[source] = source

def run(self, args):
self.depotPath = ""
self.changeRange = ""
@ -914,6 +727,9 @@ class P4Sync(Command): @@ -914,6 +727,9 @@ class P4Sync(Command):
if self.detectLabels:
self.getLabels();

if self.detectBranches:
self.getBranchMapping();

self.tz = "%+03d%02d" % (- time.timezone / 3600, ((- time.timezone % 3600) / 60))

importProcess = subprocess.Popen(["git", "fast-import"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE);
@ -993,35 +809,22 @@ class P4Sync(Command): @@ -993,35 +809,22 @@ class P4Sync(Command):
files = self.extractFilesFromCommit(description)
if self.detectBranches:
for branch in self.branchesForCommit(files):
self.knownBranches.add(branch)
branchPrefix = self.depotPath + branch + "/"

filesForCommit = self.extractFilesInCommitToBranch(files, branchPrefix)

merged = ""
parent = ""
########### remove cnt!!!
if branch not in self.createdBranches and cnt > 2:

filesForCommit = self.extractFilesInCommitToBranch(files, branch)

if branch not in self.createdBranches :
self.createdBranches.add(branch)
parent = self.findBranchParent(branchPrefix, files)
parent = self.knownBranches[branch]
if parent == branch:
parent = ""
# elif len(parent) > 0:
# print "%s branched off of %s" % (branch, parent)

if len(parent) == 0:
merged = self.findBranchSourceHeuristic(filesForCommit, branch, branchPrefix)
if len(merged) > 0:
print "change %s could be a merge from %s into %s" % (description["change"], merged, branch)
if not self.changeIsBranchMerge(merged, branch, int(description["change"])):
merged = ""

branch = "refs/heads/" + branch
branch = "refs/remotes/p4/" + branch
if len(parent) > 0:
parent = "refs/heads/" + parent
if len(merged) > 0:
merged = "refs/heads/" + merged
self.commit(description, files, branch, branchPrefix, parent, merged)
parent = "refs/remotes/p4/" + parent
self.commit(description, files, branch, branchPrefix, parent)
else:
self.commit(description, files, self.branch, self.depotPath, self.initialParent)
self.initialParent = ""

Loading…
Cancel
Save