optparse.make_option("--verbose", dest="verbose", action="store_true"),
optparse.make_option("--origin", dest="origin"),
optparse.make_option("--reset", action="store_true", dest="reset"),
- optparse.make_option("--log-substitutions", dest="substFile"),
- optparse.make_option("--dry-run", action="store_true"),
optparse.make_option("--direct", dest="directSubmit", action="store_true"),
- optparse.make_option("--trust-me-like-a-fool", dest="trustMeLikeAFool", action="store_true"),
optparse.make_option("-M", dest="detectRename", 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 = ""
self.directSubmit = False
- self.trustMeLikeAFool = False
self.detectRename = False
self.verbose = False
self.isWindows = (platform.system() == "Windows")
- 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.")
self.config["commits"] = commits
+ # replaces everything between 'Description:' and the next P4 submit template field with the
+ # commit message
def prepareLogMessage(self, template, message):
result = ""
+ inDescriptionSection = False
+
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 inDescriptionSection:
+ if line.startswith("Files:"):
+ inDescriptionSection = False
+ else:
+ continue
+ else:
+ if line.startswith("Description:"):
+ inDescriptionSection = True
+ line += "\n"
+ for messageLine in message.split("\n"):
+ line += "\t" + messageLine + "\n"
- if not substituted:
- result += line + "\n"
+ result += line + "\n"
return result
logMessage = ""
if not self.directSubmit:
logMessage = extractLogMessageFromGitCommit(id)
- logMessage = logMessage.replace("\n", "\n\t")
if self.isWindows:
logMessage = logMessage.replace("\n", "\r\n")
logMessage = logMessage.strip()
separatorLine += "\r"
separatorLine += "\n"
- response = "e"
- if self.trustMeLikeAFool:
- response = "y"
-
- firstIteration = True
- while response == "e":
- if not firstIteration:
- response = raw_input("Do you want to submit this change? [y]es/[e]dit/[n]o/[s]kip ")
- firstIteration = False
- if response == "e":
- [handle, fileName] = tempfile.mkstemp()
- tmpFile = os.fdopen(handle, "w+")
- tmpFile.write(submitTemplate + separatorLine + diff)
- tmpFile.close()
- defaultEditor = "vi"
- if platform.system() == "Windows":
- defaultEditor = "notepad"
- editor = os.environ.get("EDITOR", defaultEditor);
- system(editor + " " + fileName)
- tmpFile = open(fileName, "rb")
- message = tmpFile.read()
- tmpFile.close()
- os.remove(fileName)
- submitTemplate = message[:message.index(separatorLine)]
- if self.isWindows:
- submitTemplate = submitTemplate.replace("\r\n", "\n")
-
- if response == "y" or response == "yes":
- if self.dryRun:
- print submitTemplate
- raw_input("Press return to continue...")
- else:
- if self.directSubmit:
- print "Submitting to git first"
- os.chdir(self.oldWorkingDirectory)
- write_pipe("git commit -a -F -", submitTemplate)
- os.chdir(self.clientPath)
-
- write_pipe("p4 submit -i", submitTemplate)
- elif response == "s":
- for f in editedFiles:
- system("p4 revert \"%s\"" % f);
- for f in filesToAdd:
- system("p4 revert \"%s\"" % f);
- system("rm %s" %f)
- for f in filesToDelete:
- system("p4 delete \"%s\"" % f);
- return
- else:
- print "Not submitting!"
- self.interactive = False
+ [handle, fileName] = tempfile.mkstemp()
+ tmpFile = os.fdopen(handle, "w+")
+ tmpFile.write(submitTemplate + separatorLine + diff)
+ tmpFile.close()
+ defaultEditor = "vi"
+ if platform.system() == "Windows":
+ defaultEditor = "notepad"
+ editor = os.environ.get("EDITOR", defaultEditor);
+ system(editor + " " + fileName)
+ tmpFile = open(fileName, "rb")
+ message = tmpFile.read()
+ tmpFile.close()
+ os.remove(fileName)
+ submitTemplate = message[:message.index(separatorLine)]
+ if self.isWindows:
+ submitTemplate = submitTemplate.replace("\r\n", "\n")
+
+ if self.directSubmit:
+ print "Submitting to git first"
+ os.chdir(self.oldWorkingDirectory)
+ write_pipe("git commit -a -F -", submitTemplate)
+ os.chdir(self.clientPath)
+
+ write_pipe("p4 submit -i", submitTemplate)
else:
fileName = "submit.txt"
file = open(fileName, "w+")
if self.reset:
self.firstTime = True
- if len(self.substFile) > 0:
- for line in open(self.substFile, "r").readlines():
- tokens = line.strip().split("=")
- self.logSubstitutions[tokens[0]] = tokens[1]
-
self.check()
self.configFile = self.gitdir + "/p4-git-sync.cfg"
self.config = shelve.open(self.configFile, writeback=True)
sync = P4Sync()
sync.run([])
- response = raw_input("Do you want to rebase current HEAD from Perforce now using git-p4 rebase? [y]es/[n]o ")
- if response == "y" or response == "yes":
- rebase = P4Rebase()
- rebase.rebase()
+ rebase = P4Rebase()
+ rebase.rebase()
os.remove(self.configFile)
return True
self.keepRepoPath = False
self.depotPaths = None
self.p4BranchesInGit = []
+ self.cloneExclude = []
if gitConfig("git-p4.syncFromOrigin") == "false":
self.syncWithOrigin = False
def extractFilesFromCommit(self, commit):
+ self.cloneExclude = [re.sub(r"\.\.\.$", "", path)
+ for path in self.cloneExclude]
files = []
fnum = 0
while commit.has_key("depotFile%s" % fnum):
path = commit["depotFile%s" % fnum]
- found = [p for p in self.depotPaths
- if path.startswith (p)]
+ if [p for p in self.cloneExclude
+ if path.startswith (p)]:
+ found = False
+ else:
+ found = [p for p in self.depotPaths
+ if path.startswith (p)]
if not found:
fnum = fnum + 1
continue
stat = filedata[j]
j += 1
text = ''
- while j < len(filedata) and filedata[j]['code'] in ('text',
- 'binary'):
- text += filedata[j]['data']
+ while j < len(filedata) and filedata[j]['code'] in ('text', 'unicode', 'binary'):
+ tmp = filedata[j]['data']
+ if stat['type'] in ('text+ko', 'unicode+ko', 'binary+ko'):
+ tmp = re.sub(r'(?i)\$(Id|Header):[^$]*\$',r'$\1$', tmp)
+ elif stat['type'] in ('text+k', 'ktext', 'kxtext', 'unicode+k', 'binary+k'):
+ tmp = re.sub(r'(?i)\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$]*\$',r'$\1$', tmp)
+ text += tmp
j += 1
l = p4CmdList("labels %s..." % ' '.join (self.depotPaths))
if len(l) > 0 and not self.silent:
- print "Finding files belonging to labels in %s" % `self.depotPath`
+ print "Finding files belonging to labels in %s" % `self.depotPaths`
for output in l:
label = output["label"]
for branch in lostAndFoundBranches:
self.knownBranches[branch] = branch
+ def getBranchMappingFromGitBranches(self):
+ branches = p4BranchesInGit(self.importIntoRemotes)
+ for branch in branches.keys():
+ if branch == "master":
+ branch = "main"
+ else:
+ branch = branch[len(self.projectName):]
+ self.knownBranches[branch] = branch
+
def listExistingP4GitBranches(self):
# branches holds mapping from name to commit
branches = p4BranchesInGit(self.importIntoRemotes)
## FIXME - what's a P4 projectName ?
self.projectName = self.guessProjectName()
- if not self.hasOrigin:
- self.getBranchMapping();
+ if self.hasOrigin:
+ self.getBranchMappingFromGitBranches()
+ else:
+ self.getBranchMapping()
if self.verbose:
print "p4-git branches: %s" % self.p4BranchesInGit
print "initial parents: %s" % self.initialParents
return self.rebase()
def rebase(self):
+ if os.system("git update-index --refresh") != 0:
+ die("Some files in your working directory are modified and different than what is in your index. You can use git update-index <filename> to bring the index up-to-date or stash away all your changes with git stash.");
+ if len(read_pipe("git diff-index HEAD --")) > 0:
+ die("You have uncommited changes. Please commit them before rebasing or stash them away with git stash.");
+
[upstream, settings] = findUpstreamBranchPoint()
if len(upstream) == 0:
die("Cannot find upstream branchpoint for rebase")
P4Sync.__init__(self)
self.description = "Creates a new git repository and imports from Perforce into it"
self.usage = "usage: %prog [options] //depot/path[@revRange]"
- self.options.append(
+ self.options += [
optparse.make_option("--destination", dest="cloneDestination",
action='store', default=None,
- help="where to leave result of the clone"))
+ help="where to leave result of the clone"),
+ optparse.make_option("-/", dest="cloneExclude",
+ action="append", type="string",
+ help="exclude depot path")
+ ]
self.cloneDestination = None
self.needsGit = False
+ # This is required for the "append" cloneExclude action
+ def ensure_value(self, attr, value):
+ if not hasattr(self, attr) or getattr(self, attr) is None:
+ setattr(self, attr, value)
+ return getattr(self, attr)
+
def defaultDestination(self, args):
## TODO: use common prefix of args?
depotPath = args[0]
depotDir = re.sub("(@[^@]*)$", "", depotPath)
depotDir = re.sub("(#[^#]*)$", "", depotDir)
- depotDir = re.sub(r"\.\.\.$,", "", depotDir)
+ depotDir = re.sub(r"\.\.\.$", "", depotDir)
depotDir = re.sub(r"/$", "", depotDir)
return os.path.split(depotDir)[1]
self.cloneDestination = depotPaths[-1]
depotPaths = depotPaths[:-1]
+ self.cloneExclude = ["/"+p for p in self.cloneExclude]
for p in depotPaths:
if not p.startswith("//"):
return False