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)
+ sys.stderr.write('Writing pipe: %s\n' % c)
pipe = os.popen(c, 'w')
val = pipe.write(str)
if pipe.close():
- sys.stderr.write('Command %s failed\n' % c)
- sys.exit(1)
+ die('Command failed: %s' % c)
return val
def read_pipe(c, ignore_error=False):
if verbose:
- sys.stderr.write('reading pipe: %s\n' % c)
+ sys.stderr.write('Reading pipe: %s\n' % c)
pipe = os.popen(c, 'rb')
val = pipe.read()
if pipe.close() and not ignore_error:
- sys.stderr.write('Command %s failed\n' % c)
- sys.exit(1)
+ die('Command failed: %s' % c)
return val
def read_pipe_lines(c):
if verbose:
- sys.stderr.write('reading pipe: %s\n' % c)
+ sys.stderr.write('Reading pipe: %s\n' % c)
## todo: check return status
pipe = os.popen(c, 'rb')
val = pipe.readlines()
if pipe.close():
- sys.stderr.write('Command %s failed\n' % c)
- sys.exit(1)
+ die('Command failed: %s' % c)
return val
def p4CmdList(cmd):
cmd = "p4 -G %s" % cmd
+ if verbose:
+ sys.stderr.write("Opening pipe: %s\n" % cmd)
pipe = os.popen(cmd, "rb")
result = []
clientPath = clientPath[:-3]
return clientPath
-def die(msg):
- sys.stderr.write(msg + "\n")
- sys.exit(1)
-
def currentGitBranch():
return read_pipe("git name-rev HEAD").split(" ")[1].strip()
values[key] = val
- values['depot-paths'] = values.get("depot-paths").split(',')
+ paths = values.get("depot-paths")
+ if not paths:
+ paths = values.get("depot-path")
+ values['depot-paths'] = paths.split(',')
return values
def gitBranchExists(branch):
def __init__(self):
Command.__init__(self)
self.options = [
- optparse.make_option("--verbose", dest="verbose", action="store_true"),
+ 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.verbose = False
def run(self, args):
+ j = 0
for output in p4CmdList(" ".join(args)):
+ print 'Element: %d' % j
+ j += 1
print output
return True
% (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:
print "No changes in working directory to submit."
return True
patch = read_pipe("git diff -p --binary --diff-filter=ACMRTUXB HEAD")
- self.diffFile = gitdir + "/p4-git-diff"
+ self.diffFile = self.gitdir + "/p4-git-diff"
f = open(self.diffFile, "wb")
f.write(patch)
f.close();
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:
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("--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')
+ 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:
if gitConfig("git-p4.syncFromOrigin") == "false":
self.syncWithOrigin = False
- def p4File(self, depotPath):
- return read_pipe("p4 print -q \"%s\"" % depotPath)
-
def extractFilesFromCommit(self, commit):
files = []
fnum = 0
return branches
+ ## 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
+
+ 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
+ # 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)
- # 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.gitStream.write("from %s\n" % parent)
for file in files:
- path = file["path"]
-
-
- if not [p for p in branchPrefixes if path.startswith(p)]:
- continue
- rev = file["rev"]
- depotPath = path + "#" + rev
- relPath = self.stripRepoPath(path, branchPrefixes)
- action = file["action"]
-
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
- 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
- data = self.p4File(depotPath)
+ data = file['data']
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")
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
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:
- cache = open(gitdir + "/p4-usercache.txt", "rb")
+ cache = open(self.getUserCacheFilename(), "rb")
lines = cache.readlines()
cache.close()
for line in lines:
if self.verbose:
print "Label changes: %s" % self.labels.keys()
+ def guessProjectName(self):
+ for p in self.depotPaths:
+ return p [p.strip().rfind("/") + 1:]
+
def getBranchMapping(self):
## FIXME - what's a P4 projectName ?
- self.projectName = self.depotPath[self.depotPath.strip().rfind("/") + 1:]
+ self.projectName = self.guessProjectName()
for info in p4CmdList("branches"):
details = p4Cmd("branch -o %s" % info["branch"])
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:
cmdline += " --branches"
for line in read_pipe_lines(cmdline):
- lie = line.strip()
- if self.importIntoRemotes and ((not line.startswith("p4/")) or line == "p4/HEAD\n"):
- continue
+ line = line.strip()
+ ## only import to p4/
+ if not line.startswith('p4/'):
+ continue
+ branch = line
if self.importIntoRemotes:
# strip off p4
branch = re.sub ("^p4/", "", line)
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 read_pipe_lines("git rev-parse --symbolic --remotes"):
line = line.strip()
system("git fetch origin")
if len(self.branch) == 0:
- self.branch = self.refPrefix + "master"
+ self.branch = self.refPrefix + "p4/master"
if gitBranchExists("refs/heads/p4") and self.importIntoRemotes:
system("git update-ref %s refs/heads/p4" % self.branch)
system("git branch -D p4");
if not gitBranchExists(self.refPrefix + "HEAD") and self.importIntoRemotes:
system("git symbolic-ref %sHEAD %s" % (self.refPrefix, self.branch))
- ### FIXME
- if 1:
+ # TODO: should always look at previous commits,
+ # merge with previous imports, if possible.
+ if args == []:
if self.hasOrigin:
self.createOrUpdateBranchesFromOrigin()
self.listExistingP4GitBranches()
settings = extractSettingsGitLog(logMsg)
- if self.verbose:
- print "path %s change %s" % (','.join(depotPaths), change)
-
self.readOptions(settings)
if (settings.has_key('depot-paths')
and settings.has_key ('change')):
else:
paths = []
for (prev, cur) in zip(self.previousDepotPaths, depotPaths):
- for i in range(0, max(len(cur), len(prev))):
+ for i in range(0, min(len(cur), len(prev))):
if cur[i] <> prev[i]:
+ i = i - 1
break
- paths.append (cur[:i])
+ paths.append (cur[:i + 1])
self.previousDepotPaths = paths
if p4Change > 0:
self.depotPaths = sorted(self.previousDepotPaths)
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
self.changeRange = p[atIdx:]
if self.changeRange == "@all":
self.changeRange = ""
- elif self.changeRange.find(",") == -1:
+ elif ',' not in self.changeRange:
self.revision = self.changeRange
self.changeRange = ""
p = p[0:atIdx]
self.gitStream = importProcess.stdin
self.gitError = importProcess.stderr
- if len(self.revision) > 0:
+ 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()) }
+ ' '.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
#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
changes.sort()
else:
if self.verbose:
- print "Getting p4 changes for %s...%s" % (`self.depotPaths`,
+ 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)
self.cloneDestination = None
self.needsGit = False
- def run(self, args):
- global gitdir
+ 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)
+ return os.path.split(depotDir)[1]
+ def run(self, args):
if len(args) < 1:
return False
return False
if not self.cloneDestination:
- depotPath = args[0]
- depotDir = re.sub("(@[^@]*)$", "", depotPath)
- depotDir = re.sub("(#[^#]*)$", "", depotDir)
- depotDir = re.sub(r"\.\.\.$,", "", depotDir)
- depotDir = re.sub(r"/$", "", depotDir)
+ self.cloneDestination = self.defaultDestination()
- self.cloneDestination = os.path.split(depotDir)[1]
-
- print "Importing from %s into %s" % (`depotPaths`, self.cloneDestination)
+ print "Importing from %s into %s" % (', '.join(depotPaths), self.cloneDestination)
os.makedirs(self.cloneDestination)
os.chdir(self.cloneDestination)
system("git init")
- gitdir = os.getcwd() + "/.git"
+ self.gitdir = os.getcwd() + "/.git"
if not P4Sync.run(self, depotPaths):
return False
if self.branch != "master":
system("git checkout -f")
else:
print "Could not detect main branch. No checkout/master branch created."
+
return True
class HelpFormatter(optparse.IndentedHelpFormatter):
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
}
cmd = ""
cmdName = sys.argv[1]
try:
- cmd = commands[cmdName]
+ klass = commands[cmdName]
+ cmd = klass()
except KeyError:
print "unknown command %s" % cmdName
print ""
sys.exit(2)
options = cmd.options
- cmd.gitdir = gitdir
+ cmd.gitdir = os.environ.get("GIT_DIR", None)
args = sys.argv[2:]
global verbose
verbose = cmd.verbose
if cmd.needsGit:
- gitdir = cmd.gitdir
- if len(gitdir) == 0:
- gitdir = ".git"
- if not isValidGitDir(gitdir):
- gitdir = read_pipe("git rev-parse --git-dir").strip()
- if os.path.exists(gitdir):
+ 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(gitdir):
- if isValidGitDir(gitdir + "/.git"):
- gitdir += "/.git"
+ if not isValidGitDir(cmd.gitdir):
+ if isValidGitDir(cmd.gitdir + "/.git"):
+ cmd.gitdir += "/.git"
else:
- die("fatal: cannot locate git repository at %s" % gitdir)
+ die("fatal: cannot locate git repository at %s" % cmd.gitdir)
- os.environ["GIT_DIR"] = gitdir
+ os.environ["GIT_DIR"] = cmd.gitdir
if not cmd.run(args):
parser.print_help()