Skip to content

Commit b79bbed

Browse files
committed
Merge branch 'ld/p4-changes-block-size'
More Perforce row number limit workaround for "git p4". * ld/p4-changes-block-size: git-p4: fixing --changes-block-size handling git-p4: add tests for non-numeric revision range git-p4: test with limited p4 server results git-p4: additional testing of --changes-block-size
2 parents 6146179 + 1051ef0 commit b79bbed

File tree

3 files changed

+165
-31
lines changed

3 files changed

+165
-31
lines changed

git-p4.py

Lines changed: 63 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ def __str__(self):
4343
# Only labels/tags matching this will be imported/exported
4444
defaultLabelRegexp = r'[a-zA-Z0-9_\-.]+$'
4545

46+
# Grab changes in blocks of this many revisions, unless otherwise requested
47+
defaultBlockSize = 512
48+
4649
def p4_build_cmd(cmd):
4750
"""Build a suitable p4 command line.
4851
@@ -249,6 +252,10 @@ def p4_reopen(type, f):
249252
def p4_move(src, dest):
250253
p4_system(["move", "-k", wildcard_encode(src), wildcard_encode(dest)])
251254

255+
def p4_last_change():
256+
results = p4CmdList(["changes", "-m", "1"])
257+
return int(results[0]['change'])
258+
252259
def p4_describe(change):
253260
"""Make sure it returns a valid result by checking for
254261
the presence of field "time". Return a dict of the
@@ -742,43 +749,77 @@ def createOrUpdateBranchesFromOrigin(localRefPrefix = "refs/remotes/p4/", silent
742749
def originP4BranchesExist():
743750
return gitBranchExists("origin") or gitBranchExists("origin/p4") or gitBranchExists("origin/p4/master")
744751

745-
def p4ChangesForPaths(depotPaths, changeRange, block_size):
752+
753+
def p4ParseNumericChangeRange(parts):
754+
changeStart = int(parts[0][1:])
755+
if parts[1] == '#head':
756+
changeEnd = p4_last_change()
757+
else:
758+
changeEnd = int(parts[1])
759+
760+
return (changeStart, changeEnd)
761+
762+
def chooseBlockSize(blockSize):
763+
if blockSize:
764+
return blockSize
765+
else:
766+
return defaultBlockSize
767+
768+
def p4ChangesForPaths(depotPaths, changeRange, requestedBlockSize):
746769
assert depotPaths
747-
assert block_size
748770

749-
# Parse the change range into start and end
771+
# Parse the change range into start and end. Try to find integer
772+
# revision ranges as these can be broken up into blocks to avoid
773+
# hitting server-side limits (maxrows, maxscanresults). But if
774+
# that doesn't work, fall back to using the raw revision specifier
775+
# strings, without using block mode.
776+
750777
if changeRange is None or changeRange == '':
751-
changeStart = '@1'
752-
changeEnd = '#head'
778+
changeStart = 1
779+
changeEnd = p4_last_change()
780+
block_size = chooseBlockSize(requestedBlockSize)
753781
else:
754782
parts = changeRange.split(',')
755783
assert len(parts) == 2
756-
changeStart = parts[0]
757-
changeEnd = parts[1]
784+
try:
785+
(changeStart, changeEnd) = p4ParseNumericChangeRange(parts)
786+
block_size = chooseBlockSize(requestedBlockSize)
787+
except:
788+
changeStart = parts[0][1:]
789+
changeEnd = parts[1]
790+
if requestedBlockSize:
791+
die("cannot use --changes-block-size with non-numeric revisions")
792+
block_size = None
758793

759794
# Accumulate change numbers in a dictionary to avoid duplicates
760795
changes = {}
761796

762797
for p in depotPaths:
763798
# Retrieve changes a block at a time, to prevent running
764-
# into a MaxScanRows error from the server.
765-
start = changeStart
766-
end = changeEnd
767-
get_another_block = True
768-
while get_another_block:
769-
new_changes = []
799+
# into a MaxResults/MaxScanRows error from the server.
800+
801+
while True:
770802
cmd = ['changes']
771-
cmd += ['-m', str(block_size)]
772-
cmd += ["%s...%s,%s" % (p, start, end)]
803+
804+
if block_size:
805+
end = min(changeEnd, changeStart + block_size)
806+
revisionRange = "%d,%d" % (changeStart, end)
807+
else:
808+
revisionRange = "%s,%s" % (changeStart, changeEnd)
809+
810+
cmd += ["%s...@%s" % (p, revisionRange)]
811+
773812
for line in p4_read_pipe_lines(cmd):
774813
changeNum = int(line.split(" ")[1])
775-
new_changes.append(changeNum)
776814
changes[changeNum] = True
777-
if len(new_changes) == block_size:
778-
get_another_block = True
779-
end = '@' + str(min(new_changes))
780-
else:
781-
get_another_block = False
815+
816+
if not block_size:
817+
break
818+
819+
if end >= changeEnd:
820+
break
821+
822+
changeStart = end + 1
782823

783824
changelist = changes.keys()
784825
changelist.sort()
@@ -1974,7 +2015,7 @@ def __init__(self):
19742015
self.syncWithOrigin = True
19752016
self.importIntoRemotes = True
19762017
self.maxChanges = ""
1977-
self.changes_block_size = 500
2018+
self.changes_block_size = None
19782019
self.keepRepoPath = False
19792020
self.depotPaths = None
19802021
self.p4BranchesInGit = []

t/t9800-git-p4-basic.sh

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,44 @@ test_expect_success 'clone two dirs, @all, conflicting files' '
131131
)
132132
'
133133

134+
revision_ranges="2000/01/01,#head \
135+
1,2080/01/01 \
136+
2000/01/01,2080/01/01 \
137+
2000/01/01,1000 \
138+
1,1000"
139+
140+
test_expect_success 'clone using non-numeric revision ranges' '
141+
test_when_finished cleanup_git &&
142+
for r in $revision_ranges
143+
do
144+
rm -fr "$git" &&
145+
test ! -d "$git" &&
146+
git p4 clone --dest="$git" //depot@$r &&
147+
(
148+
cd "$git" &&
149+
git ls-files >lines &&
150+
test_line_count = 6 lines
151+
)
152+
done
153+
'
154+
155+
test_expect_success 'clone with date range, excluding some changes' '
156+
test_when_finished cleanup_git &&
157+
before=$(date +%Y/%m/%d:%H:%M:%S) &&
158+
sleep 2 &&
159+
(
160+
cd "$cli" &&
161+
:>date_range_test &&
162+
p4 add date_range_test &&
163+
p4 submit -d "Adding file"
164+
) &&
165+
git p4 clone --dest="$git" //depot@1,$before &&
166+
(
167+
cd "$git" &&
168+
test_path_is_missing date_range_test
169+
)
170+
'
171+
134172
test_expect_success 'exit when p4 fails to produce marshaled output' '
135173
mkdir badp4dir &&
136174
test_when_finished "rm badp4dir/p4 && rmdir badp4dir" &&

t/t9818-git-p4-block.sh

Lines changed: 64 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,34 @@ test_expect_success 'start p4d' '
88
start_p4d
99
'
1010

11-
test_expect_success 'Create a repo with ~100 changes' '
11+
create_restricted_group() {
12+
p4 group -i <<-EOF
13+
Group: restricted
14+
MaxResults: 7
15+
MaxScanRows: 40
16+
Users: author
17+
EOF
18+
}
19+
20+
test_expect_success 'Create group with limited maxrows' '
21+
create_restricted_group
22+
'
23+
24+
test_expect_success 'Create a repo with many changes' '
1225
(
13-
cd "$cli" &&
26+
client_view "//depot/included/... //client/included/..." \
27+
"//depot/excluded/... //client/excluded/..." &&
28+
mkdir -p "$cli/included" "$cli/excluded" &&
29+
cd "$cli/included" &&
1430
>file.txt &&
1531
p4 add file.txt &&
1632
p4 submit -d "Add file.txt" &&
17-
for i in $(test_seq 0 9)
33+
for i in $(test_seq 0 5)
1834
do
1935
>outer$i.txt &&
2036
p4 add outer$i.txt &&
2137
p4 submit -d "Adding outer$i.txt" &&
22-
for j in $(test_seq 0 9)
38+
for j in $(test_seq 0 5)
2339
do
2440
p4 edit file.txt &&
2541
echo $i$j >file.txt &&
@@ -29,34 +45,73 @@ test_expect_success 'Create a repo with ~100 changes' '
2945
)
3046
'
3147

48+
test_expect_success 'Default user cannot fetch changes' '
49+
! p4 changes -m 1 //depot/...
50+
'
51+
3252
test_expect_success 'Clone the repo' '
33-
git p4 clone --dest="$git" --changes-block-size=10 --verbose //depot@all
53+
git p4 clone --dest="$git" --changes-block-size=7 --verbose //depot/included@all
3454
'
3555

3656
test_expect_success 'All files are present' '
3757
echo file.txt >expected &&
3858
test_write_lines outer0.txt outer1.txt outer2.txt outer3.txt outer4.txt >>expected &&
39-
test_write_lines outer5.txt outer6.txt outer7.txt outer8.txt outer9.txt >>expected &&
59+
test_write_lines outer5.txt >>expected &&
4060
ls "$git" >current &&
4161
test_cmp expected current
4262
'
4363

4464
test_expect_success 'file.txt is correct' '
45-
echo 99 >expected &&
65+
echo 55 >expected &&
4666
test_cmp expected "$git/file.txt"
4767
'
4868

4969
test_expect_success 'Correct number of commits' '
5070
(cd "$git" && git log --oneline) >log &&
51-
test_line_count = 111 log
71+
wc -l log &&
72+
test_line_count = 43 log
5273
'
5374

5475
test_expect_success 'Previous version of file.txt is correct' '
5576
(cd "$git" && git checkout HEAD^^) &&
56-
echo 97 >expected &&
77+
echo 53 >expected &&
5778
test_cmp expected "$git/file.txt"
5879
'
5980

81+
# Test git-p4 sync, with some files outside the client specification.
82+
83+
p4_add_file() {
84+
(cd "$cli" &&
85+
>$1 &&
86+
p4 add $1 &&
87+
p4 submit -d "Added a file" $1
88+
)
89+
}
90+
91+
test_expect_success 'Add some more files' '
92+
for i in $(test_seq 0 10)
93+
do
94+
p4_add_file "included/x$i" &&
95+
p4_add_file "excluded/x$i"
96+
done &&
97+
for i in $(test_seq 0 10)
98+
do
99+
p4_add_file "excluded/y$i"
100+
done
101+
'
102+
103+
# This should pick up the 10 new files in "included", but not be confused
104+
# by the additional files in "excluded"
105+
test_expect_success 'Syncing files' '
106+
(
107+
cd "$git" &&
108+
git p4 sync --changes-block-size=7 &&
109+
git checkout p4/master &&
110+
ls -l x* > log &&
111+
test_line_count = 11 log
112+
)
113+
'
114+
60115
test_expect_success 'kill p4d' '
61116
kill_p4d
62117
'

0 commit comments

Comments
 (0)