summaryrefslogtreecommitdiff
path: root/git-p4.py
diff options
context:
space:
mode:
authorLuke Diamand <luke@diamand.org>2015-06-10 07:30:59 (GMT)
committerJunio C Hamano <gitster@pobox.com>2015-06-10 15:29:17 (GMT)
commit1051ef00636357061d72bcf673da86054fb14a12 (patch)
treeb22a0deb0f67a6249a57b4003b0e8e3287f8782b /git-p4.py
parenteceafffbec97385eb65d7ba0c365ee028aaf1aad (diff)
downloadgit-1051ef00636357061d72bcf673da86054fb14a12.zip
git-1051ef00636357061d72bcf673da86054fb14a12.tar.gz
git-1051ef00636357061d72bcf673da86054fb14a12.tar.bz2
git-p4: fixing --changes-block-size handling
The --changes-block-size handling was intended to help when a user has a limited "maxscanrows" (see "p4 group"). It used "p4 changes -m $maxchanges" to limit the number of results. Unfortunately, it turns out that the "maxscanrows" and "maxresults" limits are actually applied *before* the "-m maxchanges" parameter is considered (experimentally). Fix the block-size handling so that it gets blocks of changes limited by revision number ($Start..$Start+$N, etc). This limits the number of results early enough that both sets of tests pass. Note that many other Perforce operations can fail for the same reason (p4 print, p4 files, etc) and it's probably not possible to workaround this. In the real world, this is probably not usually a problem. Signed-off-by: Luke Diamand <luke@diamand.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'git-p4.py')
-rwxr-xr-xgit-p4.py85
1 files changed, 63 insertions, 22 deletions
diff --git a/git-p4.py b/git-p4.py
index ca6bb95..73f05f0 100755
--- a/git-p4.py
+++ b/git-p4.py
@@ -43,6 +43,9 @@ verbose = False
# Only labels/tags matching this will be imported/exported
defaultLabelRegexp = r'[a-zA-Z0-9_\-.]+$'
+# Grab changes in blocks of this many revisions, unless otherwise requested
+defaultBlockSize = 512
+
def p4_build_cmd(cmd):
"""Build a suitable p4 command line.
@@ -249,6 +252,10 @@ def p4_reopen(type, f):
def p4_move(src, dest):
p4_system(["move", "-k", wildcard_encode(src), wildcard_encode(dest)])
+def p4_last_change():
+ results = p4CmdList(["changes", "-m", "1"])
+ return int(results[0]['change'])
+
def p4_describe(change):
"""Make sure it returns a valid result by checking for
the presence of field "time". Return a dict of the
@@ -742,43 +749,77 @@ def createOrUpdateBranchesFromOrigin(localRefPrefix = "refs/remotes/p4/", silent
def originP4BranchesExist():
return gitBranchExists("origin") or gitBranchExists("origin/p4") or gitBranchExists("origin/p4/master")
-def p4ChangesForPaths(depotPaths, changeRange, block_size):
+
+def p4ParseNumericChangeRange(parts):
+ changeStart = int(parts[0][1:])
+ if parts[1] == '#head':
+ changeEnd = p4_last_change()
+ else:
+ changeEnd = int(parts[1])
+
+ return (changeStart, changeEnd)
+
+def chooseBlockSize(blockSize):
+ if blockSize:
+ return blockSize
+ else:
+ return defaultBlockSize
+
+def p4ChangesForPaths(depotPaths, changeRange, requestedBlockSize):
assert depotPaths
- assert block_size
- # Parse the change range into start and end
+ # Parse the change range into start and end. Try to find integer
+ # revision ranges as these can be broken up into blocks to avoid
+ # hitting server-side limits (maxrows, maxscanresults). But if
+ # that doesn't work, fall back to using the raw revision specifier
+ # strings, without using block mode.
+
if changeRange is None or changeRange == '':
- changeStart = '@1'
- changeEnd = '#head'
+ changeStart = 1
+ changeEnd = p4_last_change()
+ block_size = chooseBlockSize(requestedBlockSize)
else:
parts = changeRange.split(',')
assert len(parts) == 2
- changeStart = parts[0]
- changeEnd = parts[1]
+ try:
+ (changeStart, changeEnd) = p4ParseNumericChangeRange(parts)
+ block_size = chooseBlockSize(requestedBlockSize)
+ except:
+ changeStart = parts[0][1:]
+ changeEnd = parts[1]
+ if requestedBlockSize:
+ die("cannot use --changes-block-size with non-numeric revisions")
+ block_size = None
# Accumulate change numbers in a dictionary to avoid duplicates
changes = {}
for p in depotPaths:
# Retrieve changes a block at a time, to prevent running
- # into a MaxScanRows error from the server.
- start = changeStart
- end = changeEnd
- get_another_block = True
- while get_another_block:
- new_changes = []
+ # into a MaxResults/MaxScanRows error from the server.
+
+ while True:
cmd = ['changes']
- cmd += ['-m', str(block_size)]
- cmd += ["%s...%s,%s" % (p, start, end)]
+
+ if block_size:
+ end = min(changeEnd, changeStart + block_size)
+ revisionRange = "%d,%d" % (changeStart, end)
+ else:
+ revisionRange = "%s,%s" % (changeStart, changeEnd)
+
+ cmd += ["%s...@%s" % (p, revisionRange)]
+
for line in p4_read_pipe_lines(cmd):
changeNum = int(line.split(" ")[1])
- new_changes.append(changeNum)
changes[changeNum] = True
- if len(new_changes) == block_size:
- get_another_block = True
- end = '@' + str(min(new_changes))
- else:
- get_another_block = False
+
+ if not block_size:
+ break
+
+ if end >= changeEnd:
+ break
+
+ changeStart = end + 1
changelist = changes.keys()
changelist.sort()
@@ -1974,7 +2015,7 @@ class P4Sync(Command, P4UserMap):
self.syncWithOrigin = True
self.importIntoRemotes = True
self.maxChanges = ""
- self.changes_block_size = 500
+ self.changes_block_size = None
self.keepRepoPath = False
self.depotPaths = None
self.p4BranchesInGit = []