Merge branch 'git-p4' of git://repo.or.cz/git/git-p4
* 'git-p4' of git://repo.or.cz/git/git-p4: git-p4: Support usage of perforce client spec git-p4: git-p4 submit cleanups. git-p4: Removed git-p4 submit --direct. git-p4: Clean up git-p4 submit's log message handling. git-p4: Remove --log-substitutions feature. git-p4: support exclude paths
This commit is contained in:
commit
a0a80f1e8a
@ -464,71 +464,47 @@ class P4Submit(Command):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
Command.__init__(self)
|
Command.__init__(self)
|
||||||
self.options = [
|
self.options = [
|
||||||
optparse.make_option("--continue", action="store_false", dest="firstTime"),
|
|
||||||
optparse.make_option("--verbose", dest="verbose", action="store_true"),
|
optparse.make_option("--verbose", dest="verbose", action="store_true"),
|
||||||
optparse.make_option("--origin", dest="origin"),
|
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("--direct", dest="directSubmit", action="store_true"),
|
|
||||||
optparse.make_option("-M", dest="detectRename", action="store_true"),
|
optparse.make_option("-M", dest="detectRename", action="store_true"),
|
||||||
]
|
]
|
||||||
self.description = "Submit changes from git to the perforce depot."
|
self.description = "Submit changes from git to the perforce depot."
|
||||||
self.usage += " [name of git branch to submit into perforce depot]"
|
self.usage += " [name of git branch to submit into perforce depot]"
|
||||||
self.firstTime = True
|
|
||||||
self.reset = False
|
|
||||||
self.interactive = True
|
self.interactive = True
|
||||||
self.substFile = ""
|
|
||||||
self.firstTime = True
|
|
||||||
self.origin = ""
|
self.origin = ""
|
||||||
self.directSubmit = False
|
|
||||||
self.detectRename = False
|
self.detectRename = False
|
||||||
self.verbose = False
|
self.verbose = False
|
||||||
self.isWindows = (platform.system() == "Windows")
|
self.isWindows = (platform.system() == "Windows")
|
||||||
|
|
||||||
self.logSubstitutions = {}
|
|
||||||
self.logSubstitutions["<enter description here>"] = "%log%"
|
|
||||||
self.logSubstitutions["\tDetails:"] = "\tDetails: %log%"
|
|
||||||
|
|
||||||
def check(self):
|
def check(self):
|
||||||
if len(p4CmdList("opened ...")) > 0:
|
if len(p4CmdList("opened ...")) > 0:
|
||||||
die("You have files opened with perforce! Close them before starting the sync.")
|
die("You have files opened with perforce! Close them before starting the sync.")
|
||||||
|
|
||||||
def start(self):
|
# replaces everything between 'Description:' and the next P4 submit template field with the
|
||||||
if len(self.config) > 0 and not self.reset:
|
# commit message
|
||||||
die("Cannot start sync. Previous sync config found at %s\n"
|
|
||||||
"If you want to start submitting again from scratch "
|
|
||||||
"maybe you want to call git-p4 submit --reset" % self.configFile)
|
|
||||||
|
|
||||||
commits = []
|
|
||||||
if self.directSubmit:
|
|
||||||
commits.append("0")
|
|
||||||
else:
|
|
||||||
for line in read_pipe_lines("git rev-list --no-merges %s..%s" % (self.origin, self.master)):
|
|
||||||
commits.append(line.strip())
|
|
||||||
commits.reverse()
|
|
||||||
|
|
||||||
self.config["commits"] = commits
|
|
||||||
|
|
||||||
def prepareLogMessage(self, template, message):
|
def prepareLogMessage(self, template, message):
|
||||||
result = ""
|
result = ""
|
||||||
|
|
||||||
|
inDescriptionSection = False
|
||||||
|
|
||||||
for line in template.split("\n"):
|
for line in template.split("\n"):
|
||||||
if line.startswith("#"):
|
if line.startswith("#"):
|
||||||
result += line + "\n"
|
result += line + "\n"
|
||||||
continue
|
continue
|
||||||
|
|
||||||
substituted = False
|
if inDescriptionSection:
|
||||||
for key in self.logSubstitutions.keys():
|
if line.startswith("Files:"):
|
||||||
if line.find(key) != -1:
|
inDescriptionSection = False
|
||||||
value = self.logSubstitutions[key]
|
else:
|
||||||
value = value.replace("%log%", message)
|
continue
|
||||||
if value != "@remove@":
|
else:
|
||||||
result += line.replace(key, value) + "\n"
|
if line.startswith("Description:"):
|
||||||
substituted = True
|
inDescriptionSection = True
|
||||||
break
|
line += "\n"
|
||||||
|
for messageLine in message.split("\n"):
|
||||||
|
line += "\t" + messageLine + "\n"
|
||||||
|
|
||||||
if not substituted:
|
result += line + "\n"
|
||||||
result += line + "\n"
|
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@ -557,13 +533,9 @@ class P4Submit(Command):
|
|||||||
return template
|
return template
|
||||||
|
|
||||||
def applyCommit(self, id):
|
def applyCommit(self, id):
|
||||||
if self.directSubmit:
|
print "Applying %s" % (read_pipe("git log --max-count=1 --pretty=oneline %s" % id))
|
||||||
print "Applying local change in working directory/index"
|
diffOpts = ("", "-M")[self.detectRename]
|
||||||
diff = self.diffStatus
|
diff = read_pipe_lines("git diff-tree -r %s \"%s^\" \"%s\"" % (diffOpts, id, id))
|
||||||
else:
|
|
||||||
print "Applying %s" % (read_pipe("git log --max-count=1 --pretty=oneline %s" % id))
|
|
||||||
diffOpts = ("", "-M")[self.detectRename]
|
|
||||||
diff = read_pipe_lines("git diff-tree -r %s \"%s^\" \"%s\"" % (diffOpts, id, id))
|
|
||||||
filesToAdd = set()
|
filesToAdd = set()
|
||||||
filesToDelete = set()
|
filesToDelete = set()
|
||||||
editedFiles = set()
|
editedFiles = set()
|
||||||
@ -598,10 +570,7 @@ class P4Submit(Command):
|
|||||||
else:
|
else:
|
||||||
die("unknown modifier %s for %s" % (modifier, path))
|
die("unknown modifier %s for %s" % (modifier, path))
|
||||||
|
|
||||||
if self.directSubmit:
|
diffcmd = "git format-patch -k --stdout \"%s^\"..\"%s\"" % (id, id)
|
||||||
diffcmd = "cat \"%s\"" % self.diffFile
|
|
||||||
else:
|
|
||||||
diffcmd = "git format-patch -k --stdout \"%s^\"..\"%s\"" % (id, id)
|
|
||||||
patchcmd = diffcmd + " | git apply "
|
patchcmd = diffcmd + " | git apply "
|
||||||
tryPatchCmd = patchcmd + "--check -"
|
tryPatchCmd = patchcmd + "--check -"
|
||||||
applyPatchCmd = patchcmd + "--check --apply -"
|
applyPatchCmd = patchcmd + "--check --apply -"
|
||||||
@ -649,13 +618,10 @@ class P4Submit(Command):
|
|||||||
mode = filesToChangeExecBit[f]
|
mode = filesToChangeExecBit[f]
|
||||||
setP4ExecBit(f, mode)
|
setP4ExecBit(f, mode)
|
||||||
|
|
||||||
logMessage = ""
|
logMessage = extractLogMessageFromGitCommit(id)
|
||||||
if not self.directSubmit:
|
if self.isWindows:
|
||||||
logMessage = extractLogMessageFromGitCommit(id)
|
logMessage = logMessage.replace("\n", "\r\n")
|
||||||
logMessage = logMessage.replace("\n", "\n\t")
|
logMessage = logMessage.strip()
|
||||||
if self.isWindows:
|
|
||||||
logMessage = logMessage.replace("\n", "\r\n")
|
|
||||||
logMessage = logMessage.strip()
|
|
||||||
|
|
||||||
template = self.prepareSubmitTemplate()
|
template = self.prepareSubmitTemplate()
|
||||||
|
|
||||||
@ -694,12 +660,6 @@ class P4Submit(Command):
|
|||||||
if self.isWindows:
|
if self.isWindows:
|
||||||
submitTemplate = submitTemplate.replace("\r\n", "\n")
|
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)
|
write_pipe("p4 submit -i", submitTemplate)
|
||||||
else:
|
else:
|
||||||
fileName = "submit.txt"
|
fileName = "submit.txt"
|
||||||
@ -741,65 +701,33 @@ class P4Submit(Command):
|
|||||||
print "Perforce checkout for depot path %s located at %s" % (self.depotPath, self.clientPath)
|
print "Perforce checkout for depot path %s located at %s" % (self.depotPath, self.clientPath)
|
||||||
self.oldWorkingDirectory = os.getcwd()
|
self.oldWorkingDirectory = os.getcwd()
|
||||||
|
|
||||||
if self.directSubmit:
|
|
||||||
self.diffStatus = read_pipe_lines("git diff -r --name-status HEAD")
|
|
||||||
if len(self.diffStatus) == 0:
|
|
||||||
print "No changes in working directory to submit."
|
|
||||||
return True
|
|
||||||
patch = read_pipe("git diff -p --binary --diff-filter=ACMRTUXB HEAD")
|
|
||||||
self.diffFile = self.gitdir + "/p4-git-diff"
|
|
||||||
f = open(self.diffFile, "wb")
|
|
||||||
f.write(patch)
|
|
||||||
f.close();
|
|
||||||
|
|
||||||
os.chdir(self.clientPath)
|
os.chdir(self.clientPath)
|
||||||
print "Syncronizing p4 checkout..."
|
print "Syncronizing p4 checkout..."
|
||||||
system("p4 sync ...")
|
system("p4 sync ...")
|
||||||
|
|
||||||
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.check()
|
||||||
self.configFile = self.gitdir + "/p4-git-sync.cfg"
|
|
||||||
self.config = shelve.open(self.configFile, writeback=True)
|
|
||||||
|
|
||||||
if self.firstTime:
|
commits = []
|
||||||
self.start()
|
for line in read_pipe_lines("git rev-list --no-merges %s..%s" % (self.origin, self.master)):
|
||||||
|
commits.append(line.strip())
|
||||||
commits = self.config.get("commits", [])
|
commits.reverse()
|
||||||
|
|
||||||
while len(commits) > 0:
|
while len(commits) > 0:
|
||||||
self.firstTime = False
|
|
||||||
commit = commits[0]
|
commit = commits[0]
|
||||||
commits = commits[1:]
|
commits = commits[1:]
|
||||||
self.config["commits"] = commits
|
|
||||||
self.applyCommit(commit)
|
self.applyCommit(commit)
|
||||||
if not self.interactive:
|
if not self.interactive:
|
||||||
break
|
break
|
||||||
|
|
||||||
self.config.close()
|
|
||||||
|
|
||||||
if self.directSubmit:
|
|
||||||
os.remove(self.diffFile)
|
|
||||||
|
|
||||||
if len(commits) == 0:
|
if len(commits) == 0:
|
||||||
if self.firstTime:
|
print "All changes applied!"
|
||||||
print "No changes found to apply between %s and current HEAD" % self.origin
|
os.chdir(self.oldWorkingDirectory)
|
||||||
else:
|
|
||||||
print "All changes applied!"
|
|
||||||
os.chdir(self.oldWorkingDirectory)
|
|
||||||
|
|
||||||
sync = P4Sync()
|
sync = P4Sync()
|
||||||
sync.run([])
|
sync.run([])
|
||||||
|
|
||||||
rebase = P4Rebase()
|
rebase = P4Rebase()
|
||||||
rebase.rebase()
|
rebase.rebase()
|
||||||
os.remove(self.configFile)
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@ -817,7 +745,9 @@ class P4Sync(Command):
|
|||||||
help="Import into refs/heads/ , not refs/remotes"),
|
help="Import into refs/heads/ , not refs/remotes"),
|
||||||
optparse.make_option("--max-changes", dest="maxChanges"),
|
optparse.make_option("--max-changes", dest="maxChanges"),
|
||||||
optparse.make_option("--keep-path", dest="keepRepoPath", action='store_true',
|
optparse.make_option("--keep-path", dest="keepRepoPath", action='store_true',
|
||||||
help="Keep entire BRANCH/DIR/SUBDIR prefix during import")
|
help="Keep entire BRANCH/DIR/SUBDIR prefix during import"),
|
||||||
|
optparse.make_option("--use-client-spec", dest="useClientSpec", action='store_true',
|
||||||
|
help="Only sync files that are included in the Perforce Client Spec")
|
||||||
]
|
]
|
||||||
self.description = """Imports from Perforce into a git repository.\n
|
self.description = """Imports from Perforce into a git repository.\n
|
||||||
example:
|
example:
|
||||||
@ -843,18 +773,27 @@ class P4Sync(Command):
|
|||||||
self.keepRepoPath = False
|
self.keepRepoPath = False
|
||||||
self.depotPaths = None
|
self.depotPaths = None
|
||||||
self.p4BranchesInGit = []
|
self.p4BranchesInGit = []
|
||||||
|
self.cloneExclude = []
|
||||||
|
self.useClientSpec = False
|
||||||
|
self.clientSpecDirs = []
|
||||||
|
|
||||||
if gitConfig("git-p4.syncFromOrigin") == "false":
|
if gitConfig("git-p4.syncFromOrigin") == "false":
|
||||||
self.syncWithOrigin = False
|
self.syncWithOrigin = False
|
||||||
|
|
||||||
def extractFilesFromCommit(self, commit):
|
def extractFilesFromCommit(self, commit):
|
||||||
|
self.cloneExclude = [re.sub(r"\.\.\.$", "", path)
|
||||||
|
for path in self.cloneExclude]
|
||||||
files = []
|
files = []
|
||||||
fnum = 0
|
fnum = 0
|
||||||
while commit.has_key("depotFile%s" % fnum):
|
while commit.has_key("depotFile%s" % fnum):
|
||||||
path = commit["depotFile%s" % fnum]
|
path = commit["depotFile%s" % fnum]
|
||||||
|
|
||||||
found = [p for p in self.depotPaths
|
if [p for p in self.cloneExclude
|
||||||
if path.startswith (p)]
|
if path.startswith (p)]:
|
||||||
|
found = False
|
||||||
|
else:
|
||||||
|
found = [p for p in self.depotPaths
|
||||||
|
if path.startswith (p)]
|
||||||
if not found:
|
if not found:
|
||||||
fnum = fnum + 1
|
fnum = fnum + 1
|
||||||
continue
|
continue
|
||||||
@ -911,11 +850,21 @@ class P4Sync(Command):
|
|||||||
|
|
||||||
## Should move this out, doesn't use SELF.
|
## Should move this out, doesn't use SELF.
|
||||||
def readP4Files(self, files):
|
def readP4Files(self, files):
|
||||||
|
for f in files:
|
||||||
|
for val in self.clientSpecDirs:
|
||||||
|
if f['path'].startswith(val[0]):
|
||||||
|
if val[1] > 0:
|
||||||
|
f['include'] = True
|
||||||
|
else:
|
||||||
|
f['include'] = False
|
||||||
|
break
|
||||||
|
|
||||||
files = [f for f in files
|
files = [f for f in files
|
||||||
if f['action'] != 'delete']
|
if f['action'] != 'delete' and
|
||||||
|
(f.has_key('include') == False or f['include'] == True)]
|
||||||
|
|
||||||
if not files:
|
if not files:
|
||||||
return
|
return []
|
||||||
|
|
||||||
filedata = p4CmdList('-x - print',
|
filedata = p4CmdList('-x - print',
|
||||||
stdin='\n'.join(['%s#%s' % (f['path'], f['rev'])
|
stdin='\n'.join(['%s#%s' % (f['path'], f['rev'])
|
||||||
@ -950,6 +899,7 @@ class P4Sync(Command):
|
|||||||
for f in files:
|
for f in files:
|
||||||
assert not f.has_key('data')
|
assert not f.has_key('data')
|
||||||
f['data'] = contents[f['path']]
|
f['data'] = contents[f['path']]
|
||||||
|
return files
|
||||||
|
|
||||||
def commit(self, details, files, branch, branchPrefixes, parent = ""):
|
def commit(self, details, files, branch, branchPrefixes, parent = ""):
|
||||||
epoch = details["time"]
|
epoch = details["time"]
|
||||||
@ -966,11 +916,7 @@ class P4Sync(Command):
|
|||||||
new_files.append (f)
|
new_files.append (f)
|
||||||
else:
|
else:
|
||||||
sys.stderr.write("Ignoring file outside of prefix: %s\n" % path)
|
sys.stderr.write("Ignoring file outside of prefix: %s\n" % path)
|
||||||
files = new_files
|
files = self.readP4Files(new_files)
|
||||||
self.readP4Files(files)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
self.gitStream.write("commit %s\n" % branch)
|
self.gitStream.write("commit %s\n" % branch)
|
||||||
# gitStream.write("mark :%s\n" % details["change"])
|
# gitStream.write("mark :%s\n" % details["change"])
|
||||||
@ -1385,6 +1331,26 @@ class P4Sync(Command):
|
|||||||
print self.gitError.read()
|
print self.gitError.read()
|
||||||
|
|
||||||
|
|
||||||
|
def getClientSpec(self):
|
||||||
|
specList = p4CmdList( "client -o" )
|
||||||
|
temp = {}
|
||||||
|
for entry in specList:
|
||||||
|
for k,v in entry.iteritems():
|
||||||
|
if k.startswith("View"):
|
||||||
|
if v.startswith('"'):
|
||||||
|
start = 1
|
||||||
|
else:
|
||||||
|
start = 0
|
||||||
|
index = v.find("...")
|
||||||
|
v = v[start:index]
|
||||||
|
if v.startswith("-"):
|
||||||
|
v = v[1:]
|
||||||
|
temp[v] = -len(v)
|
||||||
|
else:
|
||||||
|
temp[v] = len(v)
|
||||||
|
self.clientSpecDirs = temp.items()
|
||||||
|
self.clientSpecDirs.sort( lambda x, y: abs( y[1] ) - abs( x[1] ) )
|
||||||
|
|
||||||
def run(self, args):
|
def run(self, args):
|
||||||
self.depotPaths = []
|
self.depotPaths = []
|
||||||
self.changeRange = ""
|
self.changeRange = ""
|
||||||
@ -1417,6 +1383,9 @@ class P4Sync(Command):
|
|||||||
if not gitBranchExists(self.refPrefix + "HEAD") and self.importIntoRemotes and gitBranchExists(self.branch):
|
if not gitBranchExists(self.refPrefix + "HEAD") and self.importIntoRemotes and gitBranchExists(self.branch):
|
||||||
system("git symbolic-ref %sHEAD %s" % (self.refPrefix, self.branch))
|
system("git symbolic-ref %sHEAD %s" % (self.refPrefix, self.branch))
|
||||||
|
|
||||||
|
if self.useClientSpec or gitConfig("p4.useclientspec") == "true":
|
||||||
|
self.getClientSpec()
|
||||||
|
|
||||||
# TODO: should always look at previous commits,
|
# TODO: should always look at previous commits,
|
||||||
# merge with previous imports, if possible.
|
# merge with previous imports, if possible.
|
||||||
if args == []:
|
if args == []:
|
||||||
@ -1634,13 +1603,23 @@ class P4Clone(P4Sync):
|
|||||||
P4Sync.__init__(self)
|
P4Sync.__init__(self)
|
||||||
self.description = "Creates a new git repository and imports from Perforce into it"
|
self.description = "Creates a new git repository and imports from Perforce into it"
|
||||||
self.usage = "usage: %prog [options] //depot/path[@revRange]"
|
self.usage = "usage: %prog [options] //depot/path[@revRange]"
|
||||||
self.options.append(
|
self.options += [
|
||||||
optparse.make_option("--destination", dest="cloneDestination",
|
optparse.make_option("--destination", dest="cloneDestination",
|
||||||
action='store', default=None,
|
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.cloneDestination = None
|
||||||
self.needsGit = False
|
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):
|
def defaultDestination(self, args):
|
||||||
## TODO: use common prefix of args?
|
## TODO: use common prefix of args?
|
||||||
depotPath = args[0]
|
depotPath = args[0]
|
||||||
@ -1664,6 +1643,7 @@ class P4Clone(P4Sync):
|
|||||||
self.cloneDestination = depotPaths[-1]
|
self.cloneDestination = depotPaths[-1]
|
||||||
depotPaths = depotPaths[:-1]
|
depotPaths = depotPaths[:-1]
|
||||||
|
|
||||||
|
self.cloneExclude = ["/"+p for p in self.cloneExclude]
|
||||||
for p in depotPaths:
|
for p in depotPaths:
|
||||||
if not p.startswith("//"):
|
if not p.startswith("//"):
|
||||||
return False
|
return False
|
||||||
|
Loading…
Reference in New Issue
Block a user