index aba4752d4e2a2e8146139797b6baab7e44ea0d76..d03ba0b6ad4c570e33d45538ee9e3ec84d18c4ef 100755 (executable)
#
# git-p4.py -- A tool for bidirectional operation between a Perforce depot and git.
#
#
# git-p4.py -- A tool for bidirectional operation between a Perforce depot and git.
#
-# Author: Simon Hausmann <hausmann@kde.org>
-# Copyright: 2007 Simon Hausmann <hausmann@kde.org>
+# Author: Simon Hausmann <simon@lst.de>
+# Copyright: 2007 Simon Hausmann <simon@lst.de>
# 2007 Trolltech ASA
# License: MIT <http://www.opensource.org/licenses/mit-license.php>
#
# 2007 Trolltech ASA
# License: MIT <http://www.opensource.org/licenses/mit-license.php>
#
import optparse, sys, os, marshal, popen2, subprocess, shelve
import tempfile, getopt, sha, os.path, time, platform
import re
import optparse, sys, os, marshal, popen2, subprocess, shelve
import tempfile, getopt, sha, os.path, time, platform
import re
+
from sets import Set;
from sets import Set;
-gitdir = os.environ.get("GIT_DIR", "")
+verbose = False
+
+def die(msg):
+ if verbose:
+ raise Exception(msg)
+ else:
+ sys.stderr.write(msg + "\n")
+ sys.exit(1)
+
+def write_pipe(c, str):
+ if verbose:
+ sys.stderr.write('Writing pipe: %s\n' % c)
+
+ pipe = os.popen(c, 'w')
+ val = pipe.write(str)
+ if pipe.close():
+ die('Command failed: %s' % c)
+
+ return val
+
+def read_pipe(c, ignore_error=False):
+ if verbose:
+ sys.stderr.write('Reading pipe: %s\n' % c)
+
+ pipe = os.popen(c, 'rb')
+ val = pipe.read()
+ if pipe.close() and not ignore_error:
+ die('Command failed: %s' % c)
-def mypopen(command):
- return os.popen(command, "rb");
+ return val
+
+
+def read_pipe_lines(c):
+ if verbose:
+ sys.stderr.write('Reading pipe: %s\n' % c)
+ ## todo: check return status
+ pipe = os.popen(c, 'rb')
+ val = pipe.readlines()
+ if pipe.close():
+ die('Command failed: %s' % c)
+
+ return val
+
+def system(cmd):
+ if verbose:
+ sys.stderr.write("executing %s\n" % cmd)
+ if os.system(cmd) != 0:
+ die("command failed: %s" % cmd)
def p4CmdList(cmd):
cmd = "p4 -G %s" % cmd
def p4CmdList(cmd):
cmd = "p4 -G %s" % cmd
+ if verbose:
+ sys.stderr.write("Opening pipe: %s\n" % cmd)
pipe = os.popen(cmd, "rb")
result = []
pipe = os.popen(cmd, "rb")
result = []
clientPath = clientPath[:-3]
return clientPath
clientPath = clientPath[:-3]
return clientPath
-def die(msg):
- sys.stderr.write(msg + "\n")
- sys.exit(1)
-
def currentGitBranch():
def currentGitBranch():
- return mypopen("git name-rev HEAD").read().split(" ")[1][:-1]
+ return read_pipe("git name-rev HEAD").split(" ")[1].strip()
def isValidGitDir(path):
def isValidGitDir(path):
- if os.path.exists(path + "/HEAD") and os.path.exists(path + "/refs") and os.path.exists(path + "/objects"):
+ if (os.path.exists(path + "/HEAD")
+ and os.path.exists(path + "/refs") and os.path.exists(path + "/objects")):
return True;
return False
def parseRevision(ref):
return True;
return False
def parseRevision(ref):
- return mypopen("git rev-parse %s" % ref).read()[:-1]
-
-def system(cmd):
- if os.system(cmd) != 0:
- die("command failed: %s" % cmd)
+ return read_pipe("git rev-parse %s" % ref).strip()
def extractLogMessageFromGitCommit(commit):
logMessage = ""
def extractLogMessageFromGitCommit(commit):
logMessage = ""
+
+ ## fixme: title is first line of commit, not 1st paragraph.
foundTitle = False
foundTitle = False
- for log in mypopen("git cat-file commit %s" % commit).readlines():
+ for log in read_pipe_lines("git cat-file commit %s" % commit):
if not foundTitle:
if len(log) == 1:
foundTitle = True
if not foundTitle:
if len(log) == 1:
foundTitle = True
logMessage += log
return logMessage
logMessage += log
return logMessage
-def extractDepotPathAndChangeFromGitLog(log):
+def extractSettingsGitLog(log):
values = {}
for line in log.split("\n"):
line = line.strip()
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")
+ m = re.search (r"^ *\[git-p4: (.*)\]$", line)
+ if not m:
+ continue
+
+ assignments = m.group(1).split (':')
+ for a in assignments:
+ vals = a.split ('=')
+ key = vals[0].strip()
+ val = ('='.join (vals[1:])).strip()
+ if val.endswith ('\"') and val.startswith('"'):
+ val = val[1:-1]
+
+ values[key] = val
+
+ paths = values.get("depot-paths")
+ if not paths:
+ paths = values.get("depot-path")
+ if paths:
+ values['depot-paths'] = paths.split(',')
+ return values
def gitBranchExists(branch):
def gitBranchExists(branch):
- proc = subprocess.Popen(["git", "rev-parse", branch], stderr=subprocess.PIPE, stdout=subprocess.PIPE);
+ proc = subprocess.Popen(["git", "rev-parse", branch],
+ stderr=subprocess.PIPE, stdout=subprocess.PIPE);
return proc.wait() == 0;
def gitConfig(key):
return proc.wait() == 0;
def gitConfig(key):
- return mypopen("git config %s" % key).read()[:-1]
+ return read_pipe("git config %s" % key, ignore_error=True).strip()
class Command:
def __init__(self):
class Command:
def __init__(self):
def __init__(self):
Command.__init__(self)
self.options = [
def __init__(self):
Command.__init__(self)
self.options = [
- ]
+ optparse.make_option("--verbose", dest="verbose", action="store_true",
+ default=False),
+ ]
self.description = "A tool to debug the output of p4 -G."
self.needsGit = False
self.description = "A tool to debug the output of p4 -G."
self.needsGit = False
+ self.verbose = False
def run(self, args):
def run(self, args):
+ j = 0
for output in p4CmdList(" ".join(args)):
for output in p4CmdList(" ".join(args)):
+ print 'Element: %d' % j
+ j += 1
print output
return True
print output
return True
if self.rollbackLocalBranches:
refPrefix = "refs/heads/"
if self.rollbackLocalBranches:
refPrefix = "refs/heads/"
- lines = mypopen("git rev-parse --symbolic --branches").readlines()
+ lines = read_pipe_lines("git rev-parse --symbolic --branches")
else:
refPrefix = "refs/remotes/"
else:
refPrefix = "refs/remotes/"
- lines = mypopen("git rev-parse --symbolic --remotes").readlines()
+ lines = read_pipe_lines("git rev-parse --symbolic --remotes")
for line in lines:
if self.rollbackLocalBranches or (line.startswith("p4/") and line != "p4/HEAD\n"):
for line in lines:
if self.rollbackLocalBranches or (line.startswith("p4/") and line != "p4/HEAD\n"):
- ref = refPrefix + line[:-1]
+ line = line.strip()
+ ref = refPrefix + line
log = extractLogMessageFromGitCommit(ref)
log = extractLogMessageFromGitCommit(ref)
- depotPath, change = extractDepotPathAndChangeFromGitLog(log)
+ settings = extractSettingsGitLog(log)
+
+ depotPaths = settings['depot-paths']
+ change = settings['change']
+
changed = False
changed = False
- if len(p4Cmd("changes -m 1 %s...@%s" % (depotPath, maxChange))) == 0:
+ if len(p4Cmd("changes -m 1 " + ' '.join (['%s...@%s' % (p, maxChange)
+ for p in depotPaths]))) == 0:
print "Branch %s did not exist at change %s, deleting." % (ref, maxChange)
system("git update-ref -d %s `git rev-parse %s`" % (ref, ref))
continue
print "Branch %s did not exist at change %s, deleting." % (ref, maxChange)
system("git update-ref -d %s `git rev-parse %s`" % (ref, ref))
continue
- while len(change) > 0 and int(change) > maxChange:
+ while change and int(change) > maxChange:
changed = True
if self.verbose:
print "%s is at %s ; rewinding towards %s" % (ref, change, maxChange)
system("git update-ref %s \"%s^\"" % (ref, ref))
log = extractLogMessageFromGitCommit(ref)
changed = True
if self.verbose:
print "%s is at %s ; rewinding towards %s" % (ref, change, maxChange)
system("git update-ref %s \"%s^\"" % (ref, ref))
log = extractLogMessageFromGitCommit(ref)
- depotPath, change = extractDepotPathAndChangeFromGitLog(log)
+ settings = extractSettingsGitLog(log)
+
+
+ depotPaths = settings['depot-paths']
+ change = settings['change']
if changed:
print "%s rewound to %s" % (ref, change)
if changed:
print "%s rewound to %s" % (ref, change)
Command.__init__(self)
self.options = [
optparse.make_option("--continue", action="store_false", dest="firstTime"),
Command.__init__(self)
self.options = [
optparse.make_option("--continue", action="store_false", dest="firstTime"),
+ 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("--origin", dest="origin"),
optparse.make_option("--reset", action="store_true", dest="reset"),
optparse.make_option("--log-substitutions", dest="substFile"),
self.origin = ""
self.directSubmit = False
self.trustMeLikeAFool = False
self.origin = ""
self.directSubmit = False
self.trustMeLikeAFool = False
+ self.verbose = False
+ self.isWindows = (platform.system() == "Windows")
self.logSubstitutions = {}
self.logSubstitutions["<enter description here>"] = "%log%"
self.logSubstitutions = {}
self.logSubstitutions["<enter description here>"] = "%log%"
if self.directSubmit:
commits.append("0")
else:
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])
+ 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
commits.reverse()
self.config["commits"] = commits
return result
return result
- def apply(self, id):
+ def applyCommit(self, id):
if self.directSubmit:
print "Applying local change in working directory/index"
diff = self.diffStatus
else:
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()
+ print "Applying %s" % (read_pipe("git log --max-count=1 --pretty=oneline %s" % id))
+ diff = read_pipe_lines("git diff-tree -r --name-status \"%s^\" \"%s\"" % (id, id))
filesToAdd = set()
filesToDelete = set()
editedFiles = set()
filesToAdd = set()
filesToDelete = set()
editedFiles = set()
if not self.directSubmit:
logMessage = extractLogMessageFromGitCommit(id)
logMessage = logMessage.replace("\n", "\n\t")
if not self.directSubmit:
logMessage = extractLogMessageFromGitCommit(id)
logMessage = logMessage.replace("\n", "\n\t")
- logMessage = logMessage[:-1]
+ if self.isWindows:
+ logMessage = logMessage.replace("\n", "\r\n")
+ logMessage = logMessage.strip()
- template = mypopen("p4 change -o").read()
+ template = read_pipe("p4 change -o")
if self.interactive:
submitTemplate = self.prepareLogMessage(template, logMessage)
if self.interactive:
submitTemplate = self.prepareLogMessage(template, logMessage)
- diff = mypopen("p4 diff -du ...").read()
+ diff = read_pipe("p4 diff -du ...")
for newFile in filesToAdd:
diff += "==== new file ====\n"
for newFile in filesToAdd:
diff += "==== new file ====\n"
tmpFile.close()
os.remove(fileName)
submitTemplate = message[:message.index(separatorLine)]
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:
if response == "y" or response == "yes":
if self.dryRun:
if self.directSubmit:
print "Submitting to git first"
os.chdir(self.oldWorkingDirectory)
if self.directSubmit:
print "Submitting to git first"
os.chdir(self.oldWorkingDirectory)
- pipe = os.popen("git commit -a -F -", "wb")
- pipe.write(submitTemplate)
- pipe.close()
+ write_pipe("git commit -a -F -", submitTemplate)
os.chdir(self.clientPath)
os.chdir(self.clientPath)
- pipe = os.popen("p4 submit -i", "wb")
- pipe.write(submitTemplate)
- pipe.close()
+ write_pipe("p4 submit -i", submitTemplate)
elif response == "s":
for f in editedFiles:
system("p4 revert \"%s\"" % f);
elif response == "s":
for f in editedFiles:
system("p4 revert \"%s\"" % f);
% (fileName, fileName))
def run(self, args):
% (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 gitBranchExists("refs/heads/%s" % self.master):
if len(args) == 0:
self.master = currentGitBranch()
if len(self.master) == 0 or not gitBranchExists("refs/heads/%s" % self.master):
return False
depotPath = ""
return False
depotPath = ""
- if gitBranchExists("p4"):
- [depotPath, dummy] = extractDepotPathAndChangeFromGitLog(extractLogMessageFromGitCommit("p4"))
- if len(depotPath) == 0 and gitBranchExists("origin"):
- [depotPath, dummy] = extractDepotPathAndChangeFromGitLog(extractLogMessageFromGitCommit("origin"))
+ parent = 0
+ while parent < 65535:
+ commit = "HEAD~%s" % parent
+ log = extractLogMessageFromGitCommit(commit)
+ settings = extractSettingsGitLog(log)
+ if not settings.has_key("depot-paths"):
+ parent = parent + 1
+ continue
+
+ depotPath = settings['depot-paths'][0]
+
+ if len(self.origin) == 0:
+ names = read_pipe_lines("git name-rev '--refs=refs/remotes/p4/*' '%s'" % commit)
+ if len(names) > 0:
+ # strip away the beginning of 'HEAD~42 refs/remotes/p4/foo'
+ self.origin = names[0].strip()[len(commit) + 1:]
+
+ break
+
+ if self.verbose:
+ print "Origin branch is " + self.origin
if len(depotPath) == 0:
print "Internal error: cannot locate perforce depot path from existing branches"
if len(depotPath) == 0:
print "Internal error: cannot locate perforce depot path from existing branches"
self.oldWorkingDirectory = os.getcwd()
if self.directSubmit:
self.oldWorkingDirectory = os.getcwd()
if self.directSubmit:
- self.diffStatus = mypopen("git diff -r --name-status HEAD").readlines()
+ 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
if len(self.diffStatus) == 0:
print "No changes in working directory to submit."
return True
- patch = mypopen("git diff -p --binary --diff-filter=ACMRTUXB HEAD").read()
- self.diffFile = gitdir + "/p4-git-diff"
+ 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();
f = open(self.diffFile, "wb")
f.write(patch)
f.close();
if response == "y" or response == "yes":
system("p4 sync ...")
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
if len(self.substFile) > 0:
for line in open(self.substFile, "r").readlines():
if self.reset:
self.firstTime = True
if len(self.substFile) > 0:
for line in open(self.substFile, "r").readlines():
- tokens = line[:-1].split("=")
+ tokens = line.strip().split("=")
self.logSubstitutions[tokens[0]] = tokens[1]
self.check()
self.logSubstitutions[tokens[0]] = tokens[1]
self.check()
- self.configFile = gitdir + "/p4-git-sync.cfg"
+ self.configFile = self.gitdir + "/p4-git-sync.cfg"
self.config = shelve.open(self.configFile, writeback=True)
if self.firstTime:
self.config = shelve.open(self.configFile, writeback=True)
if self.firstTime:
commit = commits[0]
commits = commits[1:]
self.config["commits"] = commits
commit = commits[0]
commits = commits[1:]
self.config["commits"] = commits
- self.apply(commit)
+ self.applyCommit(commit)
if not self.interactive:
break
if not self.interactive:
break
optparse.make_option("--silent", dest="silent", action="store_true"),
optparse.make_option("--detect-labels", dest="detectLabels", action="store_true"),
optparse.make_option("--verbose", dest="verbose", action="store_true"),
optparse.make_option("--silent", dest="silent", action="store_true"),
optparse.make_option("--detect-labels", dest="detectLabels", action="store_true"),
optparse.make_option("--verbose", dest="verbose", action="store_true"),
- optparse.make_option("--import-local", dest="importIntoRemotes", action="store_false"),
- optparse.make_option("--max-changes", dest="maxChanges")
+ optparse.make_option("--import-local", dest="importIntoRemotes", action="store_false",
+ help="Import into refs/heads/ , not refs/remotes"),
+ optparse.make_option("--max-changes", dest="maxChanges"),
+ optparse.make_option("--keep-path", dest="keepRepoPath", action='store_true',
+ help="Keep entire BRANCH/DIR/SUBDIR prefix during import")
]
self.description = """Imports from Perforce into a git repository.\n
example:
]
self.description = """Imports from Perforce into a git repository.\n
example:
(a ... is not needed in the path p4 specification, it's added implicitly)"""
self.usage += " //depot/path[@revRange]"
(a ... is not needed in the path p4 specification, it's added implicitly)"""
self.usage += " //depot/path[@revRange]"
-
self.silent = False
self.createdBranches = Set()
self.committedChanges = Set()
self.silent = False
self.createdBranches = Set()
self.committedChanges = Set()
self.importIntoRemotes = True
self.maxChanges = ""
self.isWindows = (platform.system() == "Windows")
self.importIntoRemotes = True
self.maxChanges = ""
self.isWindows = (platform.system() == "Windows")
+ self.keepRepoPath = False
+ self.depotPaths = None
if gitConfig("git-p4.syncFromOrigin") == "false":
self.syncWithOrigin = False
if gitConfig("git-p4.syncFromOrigin") == "false":
self.syncWithOrigin = False
- def p4File(self, depotPath):
- return os.popen("p4 print -q \"%s\"" % depotPath, "rb").read()
-
def extractFilesFromCommit(self, commit):
files = []
fnum = 0
while commit.has_key("depotFile%s" % fnum):
path = commit["depotFile%s" % fnum]
def extractFilesFromCommit(self, commit):
files = []
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)
+
+ found = [p for p in self.depotPaths
+ if path.startswith (p)]
+ if not found:
fnum = fnum + 1
continue
fnum = fnum + 1
continue
fnum = fnum + 1
return files
fnum = fnum + 1
return files
+ def stripRepoPath(self, path, prefixes):
+ if self.keepRepoPath:
+ prefixes = [re.sub("^(//[^/]+/).*", r'\1', prefixes[0])]
+
+ for p in prefixes:
+ if path.startswith(p):
+ path = path[len(p):]
+
+ return path
+
def splitFilesIntoBranches(self, commit):
branches = {}
def splitFilesIntoBranches(self, commit):
branches = {}
-
fnum = 0
while commit.has_key("depotFile%s" % fnum):
path = commit["depotFile%s" % fnum]
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)
+ found = [p for p in self.depotPaths
+ if path.startswith (p)]
+ if not found:
fnum = fnum + 1
continue
fnum = fnum + 1
continue
file["type"] = commit["type%s" % fnum]
fnum = fnum + 1
file["type"] = commit["type%s" % fnum]
fnum = fnum + 1
- relPath = path[len(self.depotPath):]
+ relPath = self.stripRepoPath(path, self.depotPaths)
for branch in self.knownBranches.keys():
for branch in self.knownBranches.keys():
- if relPath.startswith(branch + "/"): # add a trailing slash so that a commit into qt/4.2foo doesn't end up in qt/4.2
+
+ # add a trailing slash so that a commit into qt/4.2foo doesn't end up in qt/4.2
+ if relPath.startswith(branch + "/"):
if branch not in branches:
branches[branch] = []
branches[branch].append(file)
return branches
if branch not in branches:
branches[branch] = []
branches[branch].append(file)
return branches
- def commit(self, details, files, branch, branchPrefix, parent = ""):
+ ## Should move this out, doesn't use SELF.
+ def readP4Files(self, files):
+ files = [f for f in files
+ if f['action'] != 'delete']
+
+ if not files:
+ return
+
+ filedata = p4CmdList('print %s' % ' '.join(['"%s#%s"' % (f['path'],
+ f['rev'])
+ for f in files]))
+
+ j = 0;
+ contents = {}
+ while j < len(filedata):
+ stat = filedata[j]
+ j += 1
+ text = ''
+ while j < len(filedata) and filedata[j]['code'] in ('text',
+ 'binary'):
+ text += filedata[j]['data']
+ j += 1
+
+
+ if not stat.has_key('depotFile'):
+ sys.stderr.write("p4 print fails with: %s\n" % repr(stat))
+ continue
+
+ contents[stat['depotFile']] = text
+
+ for f in files:
+ assert not f.has_key('data')
+ f['data'] = contents[f['path']]
+
+ def commit(self, details, files, branch, branchPrefixes, parent = ""):
epoch = details["time"]
author = details["user"]
if self.verbose:
print "commit into %s" % branch
epoch = details["time"]
author = details["user"]
if self.verbose:
print "commit into %s" % branch
+ # start with reading files; if that fails, we should not
+ # create a commit.
+ new_files = []
+ for f in files:
+ if [p for p in branchPrefixes if f['path'].startswith(p)]:
+ new_files.append (f)
+ else:
+ sys.stderr.write("Ignoring file outside of prefix: %s\n" % path)
+ files = 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"])
self.committedChanges.add(int(details["change"]))
committer = ""
if author not in self.users:
self.committedChanges.add(int(details["change"]))
committer = ""
if author not in self.users:
self.gitStream.write("data <<EOT\n")
self.gitStream.write(details["desc"])
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-paths = \"%s\": change = %s: "
+ "options = %s]\n"
+ % (','.join (branchPrefixes), details["change"],
+ details['options']
+ ))
self.gitStream.write("EOT\n\n")
if len(parent) > 0:
self.gitStream.write("EOT\n\n")
if len(parent) > 0:
self.gitStream.write("from %s\n" % parent)
for file in files:
self.gitStream.write("from %s\n" % parent)
for file in files:
- path = file["path"]
- if not path.startswith(branchPrefix):
- # print "\nchanged files: ignoring path %s outside of branch prefix %s in change %s" % (path, branchPrefix, details["change"])
- continue
- rev = file["rev"]
- depotPath = path + "#" + rev
- relPath = path[len(branchPrefix):]
- action = file["action"]
-
if file["type"] == "apple":
if file["type"] == "apple":
- print "\nfile %s is a strange apple file that forks. Ignoring!" % path
+ print "\nfile %s is a strange apple file that forks. Ignoring!" % file['path']
continue
continue
- if action == "delete":
+ relPath = self.stripRepoPath(file['path'], branchPrefixes)
+ if file["action"] == "delete":
self.gitStream.write("D %s\n" % relPath)
else:
mode = 644
if file["type"].startswith("x"):
mode = 755
self.gitStream.write("D %s\n" % relPath)
else:
mode = 644
if file["type"].startswith("x"):
mode = 755
- data = self.p4File(depotPath)
+ data = file['data']
if self.isWindows and file["type"].endswith("text"):
data = data.replace("\r\n", "\n")
if self.isWindows and file["type"].endswith("text"):
data = data.replace("\r\n", "\n")
- self.gitStream.write("M %s inline %s\n" % (mode, relPath))
+ self.gitStream.write("M %d inline %s\n" % (mode, relPath))
self.gitStream.write("data %s\n" % len(data))
self.gitStream.write(data)
self.gitStream.write("\n")
self.gitStream.write("data %s\n" % len(data))
self.gitStream.write(data)
self.gitStream.write("\n")
if self.verbose:
print "Change %s is labelled %s" % (change, labelDetails)
if self.verbose:
print "Change %s is labelled %s" % (change, labelDetails)
- files = p4CmdList("files %s...@%s" % (branchPrefix, change))
+ files = p4CmdList("files " + ' '.join (["%s...@%s" % (p, change)
+ for p in branchPrefixes]))
if len(files) == len(labelRevisions):
if len(files) == len(labelRevisions):
print ("Tag %s does not match with change %s: file count is different."
% (labelDetails["label"], change))
print ("Tag %s does not match with change %s: file count is different."
% (labelDetails["label"], change))
+ def getUserCacheFilename(self):
+ return os.environ["HOME"] + "/.gitp4-usercache.txt"
+
def getUserMapFromPerforceServer(self):
if self.userMapFromPerforceServer:
return
def getUserMapFromPerforceServer(self):
if self.userMapFromPerforceServer:
return
continue
self.users[output["User"]] = output["FullName"] + " <" + output["Email"] + ">"
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();
+
+ s = ''
+ for (key, val) in self.users.items():
+ s += "%s\t%s\n" % (key, val)
+
+ open(self.getUserCacheFilename(), "wb").write(s)
self.userMapFromPerforceServer = True
def loadUserMapFromCache(self):
self.users = {}
self.userMapFromPerforceServer = False
try:
self.userMapFromPerforceServer = True
def loadUserMapFromCache(self):
self.users = {}
self.userMapFromPerforceServer = False
try:
- cache = open(gitdir + "/p4-usercache.txt", "rb")
+ cache = open(self.getUserCacheFilename(), "rb")
lines = cache.readlines()
cache.close()
for line in lines:
lines = cache.readlines()
cache.close()
for line in lines:
- entry = line[:-1].split("\t")
+ entry = line.strip().split("\t")
self.users[entry[0]] = entry[1]
except IOError:
self.getUserMapFromPerforceServer()
self.users[entry[0]] = entry[1]
except IOError:
self.getUserMapFromPerforceServer()
def getLabels(self):
self.labels = {}
def getLabels(self):
self.labels = {}
- l = p4CmdList("labels %s..." % self.depotPath)
+ l = p4CmdList("labels %s..." % ' '.join (self.depotPaths))
if len(l) > 0 and not self.silent:
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.depotPath`
for output in l:
label = output["label"]
for output in l:
label = output["label"]
newestChange = 0
if self.verbose:
print "Querying files for label %s" % label
newestChange = 0
if self.verbose:
print "Querying files for label %s" % label
- for file in p4CmdList("files %s...@%s" % (self.depotPath, label)):
+ for file in p4CmdList("files "
+ + ' '.join (["%s...@%s" % (p, label)
+ for p in self.depotPaths])):
revisions[file["depotFile"]] = file["rev"]
change = int(file["change"])
if change > newestChange:
revisions[file["depotFile"]] = file["rev"]
change = int(file["change"])
if change > newestChange:
if self.verbose:
print "Label changes: %s" % self.labels.keys()
if self.verbose:
print "Label changes: %s" % self.labels.keys()
- def getBranchMapping(self):
- self.projectName = self.depotPath[self.depotPath[:-1].rfind("/") + 1:]
+ def guessProjectName(self):
+ for p in self.depotPaths:
+ return p [p.strip().rfind("/") + 1:]
+ def getBranchMapping(self):
for info in p4CmdList("branches"):
details = p4Cmd("branch -o %s" % info["branch"])
viewIdx = 0
for info in p4CmdList("branches"):
details = p4Cmd("branch -o %s" % info["branch"])
viewIdx = 0
continue
source = paths[0]
destination = paths[1]
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]
+ ## HACK
+ if source.startswith(self.depotPaths[0]) and destination.startswith(self.depotPaths[0]):
+ source = source[len(self.depotPaths[0]):-4]
+ destination = destination[len(self.depotPaths[0]):-4]
if destination not in self.knownBranches:
self.knownBranches[destination] = source
if source not in self.knownBranches:
if destination not in self.knownBranches:
self.knownBranches[destination] = source
if source not in self.knownBranches:
else:
cmdline += " --branches"
else:
cmdline += " --branches"
- for line in mypopen(cmdline).readlines():
- if self.importIntoRemotes and ((not line.startswith("p4/")) or line == "p4/HEAD\n"):
+ for line in read_pipe_lines(cmdline):
+ line = line.strip()
+
+ ## only import to p4/
+ if not line.startswith('p4/') or line == "p4/HEAD":
continue
continue
- if self.importIntoRemotes:
- # strip off p4
- branch = line[3:-1]
- else:
- branch = line[:-1]
+ branch = line
+
+ # strip off p4
+ branch = re.sub ("^p4/", "", line)
+
self.p4BranchesInGit.append(branch)
self.p4BranchesInGit.append(branch)
- self.initialParents[self.refPrefix + branch] = parseRevision(line[:-1])
+ self.initialParents[self.refPrefix + branch] = parseRevision(line)
def createOrUpdateBranchesFromOrigin(self):
if not self.silent:
def createOrUpdateBranchesFromOrigin(self):
if not self.silent:
- print "Creating/updating branch(es) in %s based on origin branch(es)" % self.refPrefix
+ print ("Creating/updating branch(es) in %s based on origin branch(es)"
+ % self.refPrefix)
- for line in mypopen("git rev-parse --symbolic --remotes"):
- if (not line.startswith("origin/")) or line.endswith("HEAD\n"):
+ for line in read_pipe_lines("git rev-parse --symbolic --remotes"):
+ line = line.strip()
+ if (not line.startswith("origin/")) or line.endswith("HEAD"):
continue
continue
- headName = line[len("origin/"):-1]
+ headName = line[len("origin/"):]
remoteHead = self.refPrefix + headName
originHead = "origin/" + headName
remoteHead = self.refPrefix + headName
originHead = "origin/" + headName
- [originPreviousDepotPath, originP4Change] = extractDepotPathAndChangeFromGitLog(extractLogMessageFromGitCommit(originHead))
- if len(originPreviousDepotPath) == 0 or len(originP4Change) == 0:
+ original = extractSettingsGitLog(extractLogMessageFromGitCommit(originHead))
+ if (not original.has_key('depot-paths')
+ or not original.has_key('change')):
continue
update = False
continue
update = False
print "creating %s" % remoteHead
update = True
else:
print "creating %s" % remoteHead
update = True
else:
- [p4PreviousDepotPath, p4Change] = extractDepotPathAndChangeFromGitLog(extractLogMessageFromGitCommit(remoteHead))
- if len(p4Change) > 0:
- if originPreviousDepotPath == p4PreviousDepotPath:
- originP4Change = int(originP4Change)
- p4Change = int(p4Change)
+ settings = extractSettingsGitLog(extractLogMessageFromGitCommit(remoteHead))
+ if settings.has_key('change') > 0:
+ if settings['depot-paths'] == original['depot-paths']:
+ originP4Change = int(original['change'])
+ p4Change = int(settings['change'])
if originP4Change > p4Change:
if originP4Change > p4Change:
- print "%s (%s) is newer than %s (%s). Updating p4 branch from origin." % (originHead, originP4Change, remoteHead, p4Change)
+ print ("%s (%s) is newer than %s (%s). "
+ "Updating p4 branch from origin."
+ % (originHead, originP4Change,
+ remoteHead, p4Change))
update = True
else:
update = True
else:
- print "Ignoring: %s was imported from %s while %s was imported from %s" % (originHead, originPreviousDepotPath, remoteHead, p4PreviousDepotPath)
+ print ("Ignoring: %s was imported from %s while "
+ "%s was imported from %s"
+ % (originHead, ','.join(original['depot-paths']),
+ remoteHead, ','.join(settings['depot-paths'])))
if update:
system("git update-ref %s %s" % (remoteHead, originHead))
if update:
system("git update-ref %s %s" % (remoteHead, originHead))
+ def updateOptionDict(self, d):
+ option_keys = {}
+ if self.keepRepoPath:
+ option_keys['keepRepoPath'] = 1
+
+ d["options"] = ' '.join(sorted(option_keys.keys()))
+
+ def readOptions(self, d):
+ self.keepRepoPath = (d.has_key('options')
+ and ('keepRepoPath' in d['options']))
+
def run(self, args):
def run(self, args):
- self.depotPath = ""
+ self.depotPaths = []
self.changeRange = ""
self.initialParent = ""
self.changeRange = ""
self.initialParent = ""
- self.previousDepotPath = ""
+ self.previousDepotPaths = []
# map from branch depot path to parent branch
self.knownBranches = {}
# map from branch depot path to parent branch
self.knownBranches = {}
if self.importIntoRemotes:
self.refPrefix = "refs/remotes/p4/"
else:
if self.importIntoRemotes:
self.refPrefix = "refs/remotes/p4/"
else:
- self.refPrefix = "refs/heads/"
+ self.refPrefix = "refs/heads/p4/"
if self.syncWithOrigin and self.hasOrigin:
if not self.silent:
if self.syncWithOrigin and self.hasOrigin:
if not self.silent:
if not gitBranchExists(self.refPrefix + "HEAD") and self.importIntoRemotes:
system("git symbolic-ref %sHEAD %s" % (self.refPrefix, self.branch))
if not gitBranchExists(self.refPrefix + "HEAD") and self.importIntoRemotes:
system("git symbolic-ref %sHEAD %s" % (self.refPrefix, self.branch))
- if len(args) == 0:
+ # TODO: should always look at previous commits,
+ # merge with previous imports, if possible.
+ if args == []:
if self.hasOrigin:
self.createOrUpdateBranchesFromOrigin()
self.listExistingP4GitBranches()
if self.hasOrigin:
self.createOrUpdateBranchesFromOrigin()
self.listExistingP4GitBranches()
p4Change = 0
for branch in self.p4BranchesInGit:
logMsg = extractLogMessageFromGitCommit(self.refPrefix + branch)
p4Change = 0
for branch in self.p4BranchesInGit:
logMsg = extractLogMessageFromGitCommit(self.refPrefix + branch)
- (depotPath, change) = extractDepotPathAndChangeFromGitLog(logMsg)
- if self.verbose:
- print "path %s change %s" % (depotPath, change)
+ settings = extractSettingsGitLog(logMsg)
- if len(depotPath) > 0 and len(change) > 0:
- change = int(change) + 1
+ self.readOptions(settings)
+ if (settings.has_key('depot-paths')
+ and settings.has_key ('change')):
+ change = int(settings['change']) + 1
p4Change = max(p4Change, change)
p4Change = max(p4Change, change)
- if len(self.previousDepotPath) == 0:
- self.previousDepotPath = depotPath
+ depotPaths = sorted(settings['depot-paths'])
+ if self.previousDepotPaths == []:
+ self.previousDepotPaths = depotPaths
else:
else:
- i = 0
- l = min(len(self.previousDepotPath), len(depotPath))
- while i < l and self.previousDepotPath[i] == depotPath[i]:
- i = i + 1
- self.previousDepotPath = self.previousDepotPath[:i]
+ paths = []
+ for (prev, cur) in zip(self.previousDepotPaths, depotPaths):
+ for i in range(0, min(len(cur), len(prev))):
+ if cur[i] <> prev[i]:
+ i = i - 1
+ break
+
+ paths.append (cur[:i + 1])
+
+ self.previousDepotPaths = paths
if p4Change > 0:
if p4Change > 0:
- self.depotPath = self.previousDepotPath
+ self.depotPaths = sorted(self.previousDepotPaths)
self.changeRange = "@%s,#head" % p4Change
self.changeRange = "@%s,#head" % p4Change
- self.initialParent = parseRevision(self.branch)
+ if not self.detectBranches:
+ self.initialParent = parseRevision(self.branch)
if not self.silent and not self.detectBranches:
print "Performing incremental import into %s git branch" % self.branch
if not self.branch.startswith("refs/"):
self.branch = "refs/heads/" + self.branch
if not self.silent and not self.detectBranches:
print "Performing incremental import into %s git branch" % self.branch
if not self.branch.startswith("refs/"):
self.branch = "refs/heads/" + self.branch
- if len(self.depotPath) != 0:
- self.depotPath = self.depotPath[:-1]
-
- if len(args) == 0 and len(self.depotPath) != 0:
+ if len(args) == 0 and self.depotPaths:
if not self.silent:
if not self.silent:
- print "Depot path: %s" % self.depotPath
- elif len(args) != 1:
- return False
+ print "Depot paths: %s" % ' '.join(self.depotPaths)
else:
else:
- if len(self.depotPath) != 0 and self.depotPath != args[0]:
+ if self.depotPaths and self.depotPaths != args:
print ("previous import used depot path %s and now %s was specified. "
print ("previous import used depot path %s and now %s was specified. "
- "This doesn't work!" % (self.depotPath, args[0]))
+ "This doesn't work!" % (' '.join (self.depotPaths),
+ ' '.join (args)))
sys.exit(1)
sys.exit(1)
- self.depotPath = args[0]
+
+ self.depotPaths = sorted(args)
self.revision = ""
self.users = {}
self.revision = ""
self.users = {}
- if self.depotPath.find("@") != -1:
- atIdx = self.depotPath.index("@")
- self.changeRange = self.depotPath[atIdx:]
- if self.changeRange == "@all":
- self.changeRange = ""
- elif self.changeRange.find(",") == -1:
- self.revision = self.changeRange
- self.changeRange = ""
- self.depotPath = self.depotPath[0:atIdx]
- elif self.depotPath.find("#") != -1:
- hashIdx = self.depotPath.index("#")
- self.revision = self.depotPath[hashIdx:]
- self.depotPath = self.depotPath[0:hashIdx]
- elif len(self.previousDepotPath) == 0:
- self.revision = "#head"
-
- if self.depotPath.endswith("..."):
- self.depotPath = self.depotPath[:-3]
-
- if not self.depotPath.endswith("/"):
- self.depotPath += "/"
+ newPaths = []
+ for p in self.depotPaths:
+ if p.find("@") != -1:
+ atIdx = p.index("@")
+ self.changeRange = p[atIdx:]
+ if self.changeRange == "@all":
+ self.changeRange = ""
+ elif ',' not in self.changeRange:
+ self.revision = self.changeRange
+ self.changeRange = ""
+ p = p[0:atIdx]
+ elif p.find("#") != -1:
+ hashIdx = p.index("#")
+ self.revision = p[hashIdx:]
+ p = p[0:hashIdx]
+ elif self.previousDepotPaths == []:
+ self.revision = "#head"
+
+ p = re.sub ("\.\.\.$", "", p)
+ if not p.endswith("/"):
+ p += "/"
+
+ newPaths.append(p)
+
+ self.depotPaths = newPaths
+
self.loadUserMapFromCache()
self.labels = {}
self.loadUserMapFromCache()
self.labels = {}
self.getLabels();
if self.detectBranches:
self.getLabels();
if self.detectBranches:
- self.getBranchMapping();
+ ## FIXME - what's a P4 projectName ?
+ self.projectName = self.guessProjectName()
+
+ if not self.hasOrigin:
+ self.getBranchMapping();
if self.verbose:
print "p4-git branches: %s" % self.p4BranchesInGit
print "initial parents: %s" % self.initialParents
for b in self.p4BranchesInGit:
if b != "master":
if self.verbose:
print "p4-git branches: %s" % self.p4BranchesInGit
print "initial parents: %s" % self.initialParents
for b in self.p4BranchesInGit:
if b != "master":
+
+ ## FIXME
b = b[len(self.projectName):]
self.createdBranches.add(b)
self.tz = "%+03d%02d" % (- time.timezone / 3600, ((- time.timezone % 3600) / 60))
importProcess = subprocess.Popen(["git", "fast-import"],
b = b[len(self.projectName):]
self.createdBranches.add(b)
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);
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE);
self.gitOutput = importProcess.stdout
self.gitStream = importProcess.stdin
self.gitError = importProcess.stderr
self.gitOutput = importProcess.stdout
self.gitStream = importProcess.stdin
self.gitError = importProcess.stderr
- if len(self.revision) > 0:
- print "Doing initial import of %s from revision %s" % (self.depotPath, self.revision)
+ if self.revision:
+ print "Doing initial import of %s from revision %s" % (' '.join(self.depotPaths), self.revision)
details = { "user" : "git perforce import user", "time" : int(time.time()) }
details["desc"] = ("Initial import of %s from the state at revision %s"
details = { "user" : "git perforce import user", "time" : int(time.time()) }
details["desc"] = ("Initial import of %s from the state at revision %s"
- % (self.depotPath, self.revision))
+ % (' '.join(self.depotPaths), self.revision))
details["change"] = self.revision
newestRevision = 0
fileCnt = 0
details["change"] = self.revision
newestRevision = 0
fileCnt = 0
- for info in p4CmdList("files %s...%s" % (self.depotPath, self.revision)):
+ for info in p4CmdList("files "
+ + ' '.join(["%s...%s"
+ % (p, self.revision)
+ for p in self.depotPaths])):
+
+ if info['code'] == 'error':
+ sys.stderr.write("p4 returned an error: %s\n"
+ % info['data'])
+ sys.exit(1)
+
+
change = int(info["change"])
if change > newestRevision:
newestRevision = change
change = int(info["change"])
if change > newestRevision:
newestRevision = change
#fileCnt = fileCnt + 1
continue
#fileCnt = fileCnt + 1
continue
- for prop in [ "depotFile", "rev", "action", "type" ]:
+ for prop in ["depotFile", "rev", "action", "type" ]:
details["%s%s" % (prop, fileCnt)] = info[prop]
fileCnt = fileCnt + 1
details["change"] = newestRevision
details["%s%s" % (prop, fileCnt)] = info[prop]
fileCnt = fileCnt + 1
details["change"] = newestRevision
-
+ self.updateOptionDict(details)
try:
try:
- self.commit(details, self.extractFilesFromCommit(details), self.branch, self.depotPath)
+ self.commit(details, self.extractFilesFromCommit(details), self.branch, self.depotPaths)
except IOError:
print "IO error with git fast-import. Is your git version recent enough?"
print self.gitError.read()
except IOError:
print "IO error with git fast-import. Is your git version recent enough?"
print self.gitError.read()
changes.sort()
else:
if self.verbose:
changes.sort()
else:
if self.verbose:
- print "Getting p4 changes for %s...%s" % (self.depotPath, self.changeRange)
- output = mypopen("p4 changes %s...%s" % (self.depotPath, self.changeRange)).readlines()
+ print "Getting p4 changes for %s...%s" % (', '.join(self.depotPaths),
+ self.changeRange)
+ assert self.depotPaths
+ output = read_pipe_lines("p4 changes " + ' '.join (["%s...%s" % (p, self.changeRange)
+ for p in self.depotPaths]))
for line in output:
changeNum = line.split(" ")[1]
for line in output:
changeNum = line.split(" ")[1]
cnt = 1
for change in changes:
description = p4Cmd("describe %s" % change)
cnt = 1
for change in changes:
description = p4Cmd("describe %s" % change)
+ self.updateOptionDict(description)
if not self.silent:
sys.stdout.write("\rImporting revision %s (%s%%)" % (change, cnt * 100 / len(changes)))
if not self.silent:
sys.stdout.write("\rImporting revision %s (%s%%)" % (change, cnt * 100 / len(changes)))
if self.detectBranches:
branches = self.splitFilesIntoBranches(description)
for branch in branches.keys():
if self.detectBranches:
branches = self.splitFilesIntoBranches(description)
for branch in branches.keys():
- branchPrefix = self.depotPath + branch + "/"
+ ## HACK --hwn
+ branchPrefix = self.depotPaths[0] + branch + "/"
parent = ""
parent = ""
if branch == "main":
branch = "master"
else:
if branch == "main":
branch = "master"
else:
+
+ ## FIXME
branch = self.projectName + branch
if parent == "main":
parent = "master"
elif len(parent) > 0:
branch = self.projectName + branch
if parent == "main":
parent = "master"
elif len(parent) > 0:
+ ## FIXME
parent = self.projectName + parent
branch = self.refPrefix + branch
parent = self.projectName + parent
branch = self.refPrefix + branch
self.commit(description, filesForCommit, branch, branchPrefix, parent)
else:
files = self.extractFilesFromCommit(description)
self.commit(description, filesForCommit, branch, branchPrefix, parent)
else:
files = self.extractFilesFromCommit(description)
- self.commit(description, files, self.branch, self.depotPath, self.initialParent)
+ self.commit(description, files, self.branch, self.depotPaths,
+ self.initialParent)
self.initialParent = ""
except IOError:
print self.gitError.read()
self.initialParent = ""
except IOError:
print self.gitError.read()
self.options = [ ]
self.description = ("Fetches the latest revision from perforce and "
+ "rebases the current work (branch) against it")
self.options = [ ]
self.description = ("Fetches the latest revision from perforce and "
+ "rebases the current work (branch) against it")
+ self.verbose = False
def run(self, args):
sync = P4Sync()
sync.run([])
print "Rebasing the current branch"
def run(self, args):
sync = P4Sync()
sync.run([])
print "Rebasing the current branch"
- oldHead = mypopen("git rev-parse HEAD").read()[:-1]
+ oldHead = read_pipe("git rev-parse HEAD").strip()
system("git rebase p4")
system("git diff-tree --stat --summary -M %s HEAD" % oldHead)
return True
system("git rebase p4")
system("git diff-tree --stat --summary -M %s HEAD" % oldHead)
return True
def __init__(self):
P4Sync.__init__(self)
self.description = "Creates a new git repository and imports from Perforce into it"
def __init__(self):
P4Sync.__init__(self)
self.description = "Creates a new git repository and imports from Perforce into it"
- self.usage = "usage: %prog [options] //depot/path[@revRange] [directory]"
+ self.usage = "usage: %prog [options] //depot/path[@revRange]"
+ self.options.append(
+ optparse.make_option("--destination", dest="cloneDestination",
+ action='store', default=None,
+ help="where to leave result of the clone"))
+ self.cloneDestination = None
self.needsGit = False
self.needsGit = False
- def run(self, args):
- global gitdir
-
- if len(args) < 1:
- return False
+ def defaultDestination(self, args):
+ ## TODO: use common prefix of args?
depotPath = args[0]
depotPath = args[0]
- destination = ""
- if len(args) == 2:
- destination = args[1]
- elif len(args) > 2:
- return False
-
- if not depotPath.startswith("//"):
- return False
-
depotDir = re.sub("(@[^@]*)$", "", depotPath)
depotDir = re.sub("(#[^#]*)$", "", depotDir)
depotDir = re.sub(r"\.\.\.$,", "", depotDir)
depotDir = re.sub(r"/$", "", depotDir)
depotDir = re.sub("(@[^@]*)$", "", depotPath)
depotDir = re.sub("(#[^#]*)$", "", depotDir)
depotDir = re.sub(r"\.\.\.$,", "", depotDir)
depotDir = re.sub(r"/$", "", depotDir)
+ return os.path.split(depotDir)[1]
- if not destination:
- destination = os.path.split(depotDir)[-1]
+ def run(self, args):
+ if len(args) < 1:
+ return False
+
+ if self.keepRepoPath and not self.cloneDestination:
+ sys.stderr.write("Must specify destination for --keep-path\n")
+ sys.exit(1)
+
+ depotPaths = args
+
+ if not self.cloneDestination and len(depotPaths) > 1:
+ self.cloneDestination = depotPaths[-1]
+ depotPaths = depotPaths[:-1]
+
+ for p in depotPaths:
+ if not p.startswith("//"):
+ return False
+
+ if not self.cloneDestination:
+ self.cloneDestination = self.defaultDestination(args)
- print "Importing from %s into %s" % (depotPath, destination)
- os.makedirs(destination)
- os.chdir(destination)
+ print "Importing from %s into %s" % (', '.join(depotPaths), self.cloneDestination)
+ os.makedirs(self.cloneDestination)
+ os.chdir(self.cloneDestination)
system("git init")
system("git init")
- gitdir = os.getcwd() + "/.git"
- if not P4Sync.run(self, [depotPath]):
+ self.gitdir = os.getcwd() + "/.git"
+ if not P4Sync.run(self, depotPaths):
return False
if self.branch != "master":
if gitBranchExists("refs/remotes/p4/master"):
return False
if self.branch != "master":
if gitBranchExists("refs/remotes/p4/master"):
system("git checkout -f")
else:
print "Could not detect main branch. No checkout/master branch created."
system("git checkout -f")
else:
print "Could not detect main branch. No checkout/master branch created."
+
return True
class HelpFormatter(optparse.IndentedHelpFormatter):
return True
class HelpFormatter(optparse.IndentedHelpFormatter):
print ""
commands = {
print ""
commands = {
- "debug" : P4Debug(),
- "submit" : P4Submit(),
- "sync" : P4Sync(),
- "rebase" : P4Rebase(),
- "clone" : P4Clone(),
- "rollback" : P4RollBack()
+ "debug" : P4Debug,
+ "submit" : P4Submit,
+ "sync" : P4Sync,
+ "rebase" : P4Rebase,
+ "clone" : P4Clone,
+ "rollback" : P4RollBack
}
}
-if len(sys.argv[1:]) == 0:
- printUsage(commands.keys())
- sys.exit(2)
-cmd = ""
-cmdName = sys.argv[1]
-try:
- cmd = commands[cmdName]
-except KeyError:
- print "unknown command %s" % cmdName
- print ""
- printUsage(commands.keys())
- sys.exit(2)
-
-options = cmd.options
-cmd.gitdir = gitdir
-
-args = sys.argv[2:]
-
-if len(options) > 0:
- options.append(optparse.make_option("--git-dir", dest="gitdir"))
-
- 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 cmd.needsGit:
- gitdir = cmd.gitdir
- if len(gitdir) == 0:
- gitdir = ".git"
- if not isValidGitDir(gitdir):
- gitdir = mypopen("git rev-parse --git-dir").read()[:-1]
- if os.path.exists(gitdir):
- cdup = mypopen("git rev-parse --show-cdup").read()[:-1];
- if len(cdup) > 0:
- os.chdir(cdup);
-
- if not isValidGitDir(gitdir):
- if isValidGitDir(gitdir + "/.git"):
- gitdir += "/.git"
- else:
- die("fatal: cannot locate git repository at %s" % gitdir)
+def main():
+ if len(sys.argv[1:]) == 0:
+ printUsage(commands.keys())
+ sys.exit(2)
+
+ cmd = ""
+ cmdName = sys.argv[1]
+ try:
+ klass = commands[cmdName]
+ cmd = klass()
+ except KeyError:
+ print "unknown command %s" % cmdName
+ print ""
+ printUsage(commands.keys())
+ sys.exit(2)
+
+ options = cmd.options
+ cmd.gitdir = os.environ.get("GIT_DIR", None)
+
+ args = sys.argv[2:]
+
+ if len(options) > 0:
+ options.append(optparse.make_option("--git-dir", dest="gitdir"))
+
+ parser = optparse.OptionParser(cmd.usage.replace("%prog", "%prog " + cmdName),
+ options,
+ description = cmd.description,
+ formatter = HelpFormatter())
+
+ (cmd, args) = parser.parse_args(sys.argv[2:], cmd);
+ global verbose
+ verbose = cmd.verbose
+ if cmd.needsGit:
+ if cmd.gitdir == None:
+ cmd.gitdir = os.path.abspath(".git")
+ if not isValidGitDir(cmd.gitdir):
+ cmd.gitdir = read_pipe("git rev-parse --git-dir").strip()
+ if os.path.exists(cmd.gitdir):
+ cdup = read_pipe("git rev-parse --show-cdup").strip()
+ if len(cdup) > 0:
+ os.chdir(cdup);
+
+ if not isValidGitDir(cmd.gitdir):
+ if isValidGitDir(cmd.gitdir + "/.git"):
+ cmd.gitdir += "/.git"
+ else:
+ die("fatal: cannot locate git repository at %s" % cmd.gitdir)
+
+ os.environ["GIT_DIR"] = cmd.gitdir
- os.environ["GIT_DIR"] = gitdir
+ if not cmd.run(args):
+ parser.print_help()
-if not cmd.run(args):
- parser.print_help()
+if __name__ == '__main__':
+ main()