From 9f90c7335e223c26d19f3c01a6d89e6c0cd8b827 Mon Sep 17 00:00:00 2001 From: Scott Lamb Date: Sun, 15 Jul 2007 20:58:10 -0700 Subject: [PATCH 1/5] git-p4: use subprocess in p4CmdList This allows bidirectional piping - useful for "-x -" to avoid commandline arguments - and is a step toward bypassing the shell. Signed-off-by: Scott Lamb Signed-off-by: Simon Hausmann --- contrib/fast-import/git-p4 | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4 index d877150f41..d93e656155 100755 --- a/contrib/fast-import/git-p4 +++ b/contrib/fast-import/git-p4 @@ -63,21 +63,34 @@ def system(cmd): if os.system(cmd) != 0: die("command failed: %s" % cmd) -def p4CmdList(cmd): +def p4CmdList(cmd, stdin=None, stdin_mode='w+b'): cmd = "p4 -G %s" % cmd if verbose: sys.stderr.write("Opening pipe: %s\n" % cmd) - pipe = os.popen(cmd, "rb") + + # Use a temporary file to avoid deadlocks without + # subprocess.communicate(), which would put another copy + # of stdout into memory. + stdin_file = None + if stdin is not None: + stdin_file = tempfile.TemporaryFile(prefix='p4-stdin', mode=stdin_mode) + stdin_file.write(stdin) + stdin_file.flush() + stdin_file.seek(0) + + p4 = subprocess.Popen(cmd, shell=True, + stdin=stdin_file, + stdout=subprocess.PIPE) result = [] try: while True: - entry = marshal.load(pipe) + entry = marshal.load(p4.stdout) result.append(entry) except EOFError: pass - exitCode = pipe.close() - if exitCode != None: + exitCode = p4.wait() + if exitCode != 0: entry = {} entry["p4ExitCode"] = exitCode result.append(entry) From 788001908c8960daa162c32baf3dc0f9ad1c16f8 Mon Sep 17 00:00:00 2001 From: Scott Lamb Date: Sun, 15 Jul 2007 20:58:11 -0700 Subject: [PATCH 2/5] git-p4: input to "p4 files" by stdin instead of arguments This approach, suggested by Alex Riesen, bypasses the need for xargs-style argument list handling. The handling in question looks broken in a corner case with SC_ARG_MAX=4096 and final argument over 96 characters. Signed-off-by: Scott Lamb Signed-off-by: Simon Hausmann --- contrib/fast-import/git-p4 | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4 index d93e656155..54053e3f3d 100755 --- a/contrib/fast-import/git-p4 +++ b/contrib/fast-import/git-p4 @@ -725,27 +725,13 @@ class P4Sync(Command): if not files: return - # We cannot put all the files on the command line - # OS have limitations on the max lenght of arguments - # POSIX says it's 4096 bytes, default for Linux seems to be 130 K. - # and all OS from the table below seems to be higher than POSIX. - # See http://www.in-ulm.de/~mascheck/various/argmax/ - if (self.isWindows): - argmax = 2000 - else: - argmax = min(4000, os.sysconf('SC_ARG_MAX')) - - chunk = '' - filedata = [] - for i in xrange(len(files)): - f = files[i] - chunk += '"%s#%s" ' % (f['path'], f['rev']) - if len(chunk) > argmax or i == len(files)-1: - data = p4CmdList('print %s' % chunk) - if "p4ExitCode" in data[0]: - die("Problems executing p4. Error: [%d]." % (data[0]['p4ExitCode'])); - filedata.extend(data) - chunk = '' + filedata = p4CmdList('-x - print', + stdin='\n'.join(['%s#%s' % (f['path'], f['rev']) + for f in files]), + stdin_mode='w+') + if "p4ExitCode" in filedata[0]: + die("Problems executing p4. Error: [%d]." + % (filedata[0]['p4ExitCode'])); j = 0; contents = {} From 062410bb9d6553e6bc4f8fa7f0cab1ed63b75628 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 18 Jul 2007 10:56:31 +0200 Subject: [PATCH 3/5] git-p4: Cleanup, make listExistingP4Branches a global function for later use. Signed-off-by: Simon Hausmann Signed-off-by: Marius Storm-Olsen --- contrib/fast-import/git-p4 | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4 index 54053e3f3d..d4a2f14311 100755 --- a/contrib/fast-import/git-p4 +++ b/contrib/fast-import/git-p4 @@ -181,6 +181,29 @@ def gitBranchExists(branch): def gitConfig(key): return read_pipe("git config %s" % key, ignore_error=True).strip() +def p4BranchesInGit(branchesAreInRemotes = True): + branches = {} + + cmdline = "git rev-parse --symbolic " + if branchesAreInRemotes: + cmdline += " --remotes" + else: + cmdline += " --branches" + + for line in read_pipe_lines(cmdline): + line = line.strip() + + ## only import to p4/ + if not line.startswith('p4/') or line == "p4/HEAD": + continue + branch = line + + # strip off p4 + branch = re.sub ("^p4/", "", line) + + branches[branch] = parseRevision(line) + return branches + def findUpstreamBranchPoint(head = "HEAD"): settings = None branchPoint = "" From 86506fe54c8e9e5f75a73956840497e3e5744f86 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 18 Jul 2007 12:40:12 +0200 Subject: [PATCH 4/5] git-p4: Fix upstream branch detection for submit/rebase with multiple branches. Don't use git name-rev to locate the upstream git-p4 branch for rebase and submit but instead locate the branch by comparing the depot paths. name-rev may produce results like wrongbranch~12 as it uses the first match. Signed-off-by: Simon Hausmann Signed-off-by: Marius Storm-Olsen --- contrib/fast-import/git-p4 | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4 index d4a2f14311..a65f53a47b 100755 --- a/contrib/fast-import/git-p4 +++ b/contrib/fast-import/git-p4 @@ -205,26 +205,31 @@ def p4BranchesInGit(branchesAreInRemotes = True): return branches def findUpstreamBranchPoint(head = "HEAD"): + branches = p4BranchesInGit() + # map from depot-path to branch name + branchByDepotPath = {} + for branch in branches.keys(): + tip = branches[branch] + log = extractLogMessageFromGitCommit(tip) + settings = extractSettingsGitLog(log) + if settings.has_key("depot-paths"): + paths = ",".join(settings["depot-paths"]) + branchByDepotPath[paths] = "remotes/p4/" + branch + settings = None - branchPoint = "" 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 + if settings.has_key("depot-paths"): + paths = ",".join(settings["depot-paths"]) + if branchByDepotPath.has_key(paths): + return [branchByDepotPath[paths], settings] - names = read_pipe_lines("git name-rev \"--refs=refs/remotes/p4/*\" \"%s\"" % commit) - if len(names) <= 0: - continue + parent = parent + 1 - # strip away the beginning of 'HEAD~42 refs/remotes/p4/foo' - branchPoint = names[0].strip()[len(commit) + 1:] - break - - return [branchPoint, settings] + return ["", settings] class Command: def __init__(self): From 144ff46b196e49fd52b2ecf0aaa1db4c190393b9 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 18 Jul 2007 17:27:50 +0200 Subject: [PATCH 5/5] git-p4: Cleanup, used common function for listing imported p4 branches Signed-off-by: Simon Hausmann --- contrib/fast-import/git-p4 | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4 index a65f53a47b..e3404ca853 100755 --- a/contrib/fast-import/git-p4 +++ b/contrib/fast-import/git-p4 @@ -1006,27 +1006,11 @@ class P4Sync(Command): self.knownBranches[branch] = branch def listExistingP4GitBranches(self): - self.p4BranchesInGit = [] - - cmdline = "git rev-parse --symbolic " - if self.importIntoRemotes: - cmdline += " --remotes" - else: - cmdline += " --branches" - - for line in read_pipe_lines(cmdline): - line = line.strip() - - ## only import to p4/ - if not line.startswith('p4/') or line == "p4/HEAD": - continue - branch = line - - # strip off p4 - branch = re.sub ("^p4/", "", line) - - self.p4BranchesInGit.append(branch) - self.initialParents[self.refPrefix + branch] = parseRevision(line) + # branches holds mapping from name to commit + branches = p4BranchesInGit(self.importIntoRemotes) + self.p4BranchesInGit = branches.keys() + for branch in branches.keys(): + self.initialParents[self.refPrefix + branch] = branches[branch] def createOrUpdateBranchesFromOrigin(self): if not self.silent: