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("--direct", dest="directSubmit", action="store_true"),
]
self.description = "Submit changes from git to the perforce depot."
self.usage += " [name of git branch to submit into perforce depot]"
self.substFile = ""
self.firstTime = True
self.origin = ""
+ self.directSubmit = False
self.logSubstitutions = {}
self.logSubstitutions["<enter description here>"] = "%log%"
die("Cannot start sync. Previous sync config found at %s\nIf you want to start submitting again from scratch maybe you want to call git-p4 submit --reset" % self.configFile)
commits = []
- for line in mypopen("git rev-list --no-merges %s..%s" % (self.origin, self.master)).readlines():
- commits.append(line[:-1])
- commits.reverse()
+ if self.directSubmit:
+ commits.append("0")
+ else:
+ for line in mypopen("git rev-list --no-merges %s..%s" % (self.origin, self.master)).readlines():
+ commits.append(line[:-1])
+ commits.reverse()
self.config["commits"] = commits
return result
def apply(self, id):
- print "Applying %s" % (mypopen("git log --max-count=1 --pretty=oneline %s" % id).read())
- diff = mypopen("git diff-tree -r --name-status \"%s^\" \"%s\"" % (id, id)).readlines()
+ if self.directSubmit:
+ print "Applying local change in working directory/index"
+ diff = self.diffStatus
+ else:
+ print "Applying %s" % (mypopen("git log --max-count=1 --pretty=oneline %s" % id).read())
+ diff = mypopen("git diff-tree -r --name-status \"%s^\" \"%s\"" % (id, id)).readlines()
filesToAdd = set()
filesToDelete = set()
editedFiles = set()
else:
die("unknown modifier %s for %s" % (modifier, path))
- diffcmd = "git diff-tree -p --diff-filter=ACMRTUXB \"%s^\" \"%s\"" % (id, id)
- patchcmd = diffcmd + " | patch -p1"
+ if self.directSubmit:
+ diffcmd = "cat \"%s\"" % self.diffFile
+ else:
+ diffcmd = "git format-patch -k --stdout \"%s^\"..\"%s\"" % (id, id)
+ patchcmd = diffcmd + " | git apply "
+ tryPatchCmd = patchcmd + "--check -"
+ applyPatchCmd = patchcmd + "--check --apply -"
- if os.system(patchcmd + " --dry-run --silent") != 0:
+ if os.system(tryPatchCmd) != 0:
print "Unfortunately applying the change failed!"
print "What do you want to do?"
response = "x"
print "Skipping! Good luck with the next patches..."
return
elif response == "a":
- os.system(patchcmd)
+ os.system(applyPatchCmd)
if len(filesToAdd) > 0:
print "You may also want to call p4 add on the following files:"
print " ".join(filesToAdd)
print "Patch saved to patch.txt in %s !" % self.clientPath
die("Please resolve and submit the conflict manually and continue afterwards with git-p4 submit --continue")
- system(patchcmd)
+ system(applyPatchCmd)
for f in filesToAdd:
system("p4 add %s" % f)
system("p4 revert %s" % f)
system("p4 delete %s" % f)
- logMessage = extractLogMessageFromGitCommit(id)
- logMessage = logMessage.replace("\n", "\n\t")
- logMessage = logMessage[:-1]
+ logMessage = ""
+ if not self.directSubmit:
+ logMessage = extractLogMessageFromGitCommit(id)
+ logMessage = logMessage.replace("\n", "\n\t")
+ logMessage = logMessage[:-1]
template = mypopen("p4 change -o").read()
print "Perforce checkout for depot path %s located at %s" % (depotPath, self.clientPath)
oldWorkingDirectory = os.getcwd()
+
+ if self.directSubmit:
+ self.diffStatus = mypopen("git diff -r --name-status HEAD").readlines()
+ patch = mypopen("git diff -p --binary --diff-filter=ACMRTUXB HEAD").read()
+ self.diffFile = gitdir + "/p4-git-diff"
+ f = open(self.diffFile, "wb")
+ f.write(patch)
+ f.close();
+
os.chdir(self.clientPath)
response = raw_input("Do you want to sync %s with p4 sync? [y]es/[n]o " % self.clientPath)
if response == "y" or response == "yes":
self.config.close()
+ if self.directSubmit:
+ os.remove(self.diffFile)
+
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!"
- response = raw_input("Do you want to sync from Perforce now using git-p4 rebase? [y]es/[n]o ")
+ response = ""
+ os.chdir(oldWorkingDirectory)
+
+ if self.directSubmit:
+ response = raw_input("Do you want to DISCARD your git WORKING DIRECTORY CHANGES and sync from Perforce now using git-p4 rebase? [y]es/[n]o ")
+ if response == "y" or response == "yes":
+ system("git reset --hard")
+
+ if len(response) == 0:
+ response = raw_input("Do you want to sync from Perforce now using git-p4 rebase? [y]es/[n]o ")
if response == "y" or response == "yes":
- os.chdir(oldWorkingDirectory)
rebase = P4Rebase()
rebase.run([])
os.remove(self.configFile)
fnum = fnum + 1
return files
- def splitFilesIntoBranches(self, files):
+ def splitFilesIntoBranches(self, commit):
branches = {}
- for file in files:
- path = file["path"][len(self.depotPath):]
+ fnum = 0
+ while commit.has_key("depotFile%s" % fnum):
+ path = commit["depotFile%s" % fnum]
+ if not path.startswith(self.depotPath):
+ # if not self.silent:
+ # print "\nchanged files: ignoring path %s outside of %s in change %s" % (path, self.depotPath, change)
+ fnum = fnum + 1
+ continue
+
+ file = {}
+ file["path"] = path
+ file["rev"] = commit["rev%s" % fnum]
+ file["action"] = commit["action%s" % fnum]
+ file["type"] = commit["type%s" % fnum]
+ fnum = fnum + 1
+
+ relPath = path[len(self.depotPath):]
for branch in self.knownBranches.keys():
- if path.startswith(branch):
+ if relPath.startswith(branch):
if branch not in branches:
branches[branch] = []
- branches[branch].append(file["path"])
+ branches[branch].append(file)
return branches
# gitStream.write("mark :%s\n" % details["change"])
self.committedChanges.add(int(details["change"]))
committer = ""
+ if author not in self.users:
+ self.getUserMapFromPerforceServer()
if author in self.users:
committer = "%s %s %s" % (self.users[author], epoch, self.tz)
else:
change = int(details["change"])
- self.lastChange = change
-
- if change in self.labels:
+ if self.labels.has_key(change):
label = self.labels[change]
labelDetails = label[0]
labelRevisions = label[1]
+ if self.verbose:
+ print "Change %s is labelled %s" % (change, labelDetails)
files = p4CmdList("files %s...@%s" % (branchPrefix, change))
if not self.silent:
print "Tag %s does not match with change %s: file count is different." % (labelDetails["label"], change)
- def getUserMap(self):
+ def getUserMapFromPerforceServer(self):
self.users = {}
for output in p4CmdList("users"):
continue
self.users[output["User"]] = output["FullName"] + " <" + output["Email"] + ">"
+ cache = open(gitdir + "/p4-usercache.txt", "wb")
+ for user in self.users.keys():
+ cache.write("%s\t%s\n" % (user, self.users[user]))
+ cache.close();
+
+ def loadUserMapFromCache(self):
+ self.users = {}
+ try:
+ cache = open(gitdir + "/p4-usercache.txt", "rb")
+ lines = cache.readlines()
+ cache.close()
+ for line in lines:
+ entry = line[:-1].split("\t")
+ self.users[entry[0]] = entry[1]
+ except IOError:
+ self.getUserMapFromPerforceServer()
+
def getLabels(self):
self.labels = {}
label = output["label"]
revisions = {}
newestChange = 0
- for file in p4CmdList("files //...@%s" % label):
+ if self.verbose:
+ print "Querying files for label %s" % label
+ for file in p4CmdList("files %s...@%s" % (self.depotPath, label)):
revisions[file["depotFile"]] = file["rev"]
change = int(file["change"])
if change > newestChange:
self.labels[newestChange] = [output, revisions]
+ if self.verbose:
+ print "Label changes: %s" % self.labels.keys()
+
def getBranchMapping(self):
self.projectName = self.depotPath[self.depotPath[:-1].rfind("/") + 1:]
self.initialParents = {}
self.listExistingP4GitBranches()
+ if len(self.p4BranchesInGit) > 1:
+ print "Importing from/into multiple branches"
+ self.detectBranches = True
if self.syncWithOrigin and gitBranchExists("origin") and gitBranchExists("refs/remotes/p4/master") and not self.detectBranches:
### needs to be ported to multi branch import
self.revision = ""
self.users = {}
- self.lastChange = 0
if self.depotPath.find("@") != -1:
atIdx = self.depotPath.index("@")
if not self.depotPath.endswith("/"):
self.depotPath += "/"
- self.getUserMap()
+ self.loadUserMapFromCache()
self.labels = {}
if self.detectLabels:
self.getLabels();
cnt = cnt + 1
try:
- files = self.extractFilesFromCommit(description)
if self.detectBranches:
- branches = self.splitFilesIntoBranches(files)
+ branches = self.splitFilesIntoBranches(description)
for branch in branches.keys():
branchPrefix = self.depotPath + branch + "/"
parent = self.initialParents[branch]
del self.initialParents[branch]
- self.commit(description, files, branch, branchPrefix, parent)
+ self.commit(description, filesForCommit, branch, branchPrefix, parent)
else:
+ files = self.extractFilesFromCommit(description)
self.commit(description, files, self.branch, self.depotPath, self.initialParent)
self.initialParent = ""
except IOError:
self.needsGit = False
def run(self, args):
+ global gitdir
+
if len(args) < 1:
return False
depotPath = args[0]
os.makedirs(dir)
os.chdir(dir)
system("git init")
+ gitdir = os.getcwd() + "/.git"
if not P4Sync.run(self, [depotPath]):
return False
if self.branch != "master":