Skip to content

Commit 44275f5

Browse files
committed
Merge branch 'am/p4-branches-excludes'
"git p4" update. * am/p4-branches-excludes: git-p4: respect excluded paths when detecting branches git-p4: add failing test for "git-p4: respect excluded paths when detecting branches" git-p4: don't exclude other files with same prefix git-p4: add failing test for "don't exclude other files with same prefix" git-p4: don't groom exclude path list on every commit git-p4: match branches case insensitively if configured git-p4: add failing test for "git-p4: match branches case insensitively if configured" git-p4: detect/prevent infinite loop in gitCommitByP4Change()
2 parents 99af5be + d15068a commit 44275f5

File tree

3 files changed

+205
-22
lines changed

3 files changed

+205
-22
lines changed

git-p4.py

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1316,7 +1316,7 @@ def __init__(self):
13161316
self.needsGit = True
13171317
self.verbose = False
13181318

1319-
# This is required for the "append" cloneExclude action
1319+
# This is required for the "append" update_shelve action
13201320
def ensure_value(self, attr, value):
13211321
if not hasattr(self, attr) or getattr(self, attr) is None:
13221322
setattr(self, attr, value)
@@ -2530,6 +2530,11 @@ def map_in_client(self, depot_path):
25302530
die( "Error: %s is not found in client spec path" % depot_path )
25312531
return ""
25322532

2533+
def cloneExcludeCallback(option, opt_str, value, parser):
2534+
# prepend "/" because the first "/" was consumed as part of the option itself.
2535+
# ("-//depot/A/..." becomes "/depot/A/..." after option parsing)
2536+
parser.values.cloneExclude += ["/" + re.sub(r"\.\.\.$", "", value)]
2537+
25332538
class P4Sync(Command, P4UserMap):
25342539

25352540
def __init__(self):
@@ -2553,7 +2558,7 @@ def __init__(self):
25532558
optparse.make_option("--use-client-spec", dest="useClientSpec", action='store_true',
25542559
help="Only sync files that are included in the Perforce Client Spec"),
25552560
optparse.make_option("-/", dest="cloneExclude",
2556-
action="append", type="string",
2561+
action="callback", callback=cloneExcludeCallback, type="string",
25572562
help="exclude depot path"),
25582563
]
25592564
self.description = """Imports from Perforce into a git repository.\n
@@ -2618,20 +2623,25 @@ def checkpoint(self):
26182623
if self.verbose:
26192624
print("checkpoint finished: " + out)
26202625

2626+
def isPathWanted(self, path):
2627+
for p in self.cloneExclude:
2628+
if p.endswith("/"):
2629+
if p4PathStartsWith(path, p):
2630+
return False
2631+
# "-//depot/file1" without a trailing "/" should only exclude "file1", but not "file111" or "file1_dir/file2"
2632+
elif path.lower() == p.lower():
2633+
return False
2634+
for p in self.depotPaths:
2635+
if p4PathStartsWith(path, p):
2636+
return True
2637+
return False
2638+
26212639
def extractFilesFromCommit(self, commit, shelved=False, shelved_cl = 0):
2622-
self.cloneExclude = [re.sub(r"\.\.\.$", "", path)
2623-
for path in self.cloneExclude]
26242640
files = []
26252641
fnum = 0
26262642
while "depotFile%s" % fnum in commit:
26272643
path = commit["depotFile%s" % fnum]
2628-
2629-
if [p for p in self.cloneExclude
2630-
if p4PathStartsWith(path, p)]:
2631-
found = False
2632-
else:
2633-
found = [p for p in self.depotPaths
2634-
if p4PathStartsWith(path, p)]
2644+
found = self.isPathWanted(path)
26352645
if not found:
26362646
fnum = fnum + 1
26372647
continue
@@ -2668,7 +2678,7 @@ def stripRepoPath(self, path, prefixes):
26682678
path = self.clientSpecDirs.map_in_client(path)
26692679
if self.detectBranches:
26702680
for b in self.knownBranches:
2671-
if path.startswith(b + "/"):
2681+
if p4PathStartsWith(path, b + "/"):
26722682
path = path[len(b)+1:]
26732683

26742684
elif self.keepRepoPath:
@@ -2700,8 +2710,7 @@ def splitFilesIntoBranches(self, commit):
27002710
fnum = 0
27012711
while "depotFile%s" % fnum in commit:
27022712
path = commit["depotFile%s" % fnum]
2703-
found = [p for p in self.depotPaths
2704-
if p4PathStartsWith(path, p)]
2713+
found = self.isPathWanted(path)
27052714
if not found:
27062715
fnum = fnum + 1
27072716
continue
@@ -2723,7 +2732,7 @@ def splitFilesIntoBranches(self, commit):
27232732
for branch in self.knownBranches.keys():
27242733
# add a trailing slash so that a commit into qt/4.2foo
27252734
# doesn't end up in qt/4.2, e.g.
2726-
if relPath.startswith(branch + "/"):
2735+
if p4PathStartsWith(relPath, branch + "/"):
27272736
if branch not in branches:
27282737
branches[branch] = []
27292738
branches[branch].append(file)
@@ -3325,7 +3334,9 @@ def gitCommitByP4Change(self, ref, change):
33253334
if currentChange < change:
33263335
earliestCommit = "^%s" % next
33273336
else:
3328-
latestCommit = "%s" % next
3337+
if next == latestCommit:
3338+
die("Infinite loop while looking in ref %s for change %s. Check your branch mappings" % (ref, change))
3339+
latestCommit = "%s^@" % next
33293340

33303341
return ""
33313342

@@ -3888,7 +3899,6 @@ def run(self, args):
38883899
self.cloneDestination = depotPaths[-1]
38893900
depotPaths = depotPaths[:-1]
38903901

3891-
self.cloneExclude = ["/"+p for p in self.cloneExclude]
38923902
for p in depotPaths:
38933903
if not p.startswith("//"):
38943904
sys.stderr.write('Depot paths must start with "//": %s\n' % p)

t/t9801-git-p4-branch.sh

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,46 @@ test_expect_failure 'git p4 clone file subset branch' '
411411
)
412412
'
413413

414+
# Check that excluded files are omitted during import
415+
test_expect_success 'git p4 clone complex branches with excluded files' '
416+
test_when_finished cleanup_git &&
417+
test_create_repo "$git" &&
418+
(
419+
cd "$git" &&
420+
git config git-p4.branchList branch1:branch2 &&
421+
git config --add git-p4.branchList branch1:branch3 &&
422+
git config --add git-p4.branchList branch1:branch4 &&
423+
git config --add git-p4.branchList branch1:branch5 &&
424+
git config --add git-p4.branchList branch1:branch6 &&
425+
git p4 clone --dest=. --detect-branches -//depot/branch1/file2 -//depot/branch2/file2 -//depot/branch3/file2 -//depot/branch4/file2 -//depot/branch5/file2 -//depot/branch6/file2 //depot@all &&
426+
git log --all --graph --decorate --stat &&
427+
git reset --hard p4/depot/branch1 &&
428+
test_path_is_file file1 &&
429+
test_path_is_missing file2 &&
430+
test_path_is_file file3 &&
431+
git reset --hard p4/depot/branch2 &&
432+
test_path_is_file file1 &&
433+
test_path_is_missing file2 &&
434+
test_path_is_missing file3 &&
435+
git reset --hard p4/depot/branch3 &&
436+
test_path_is_file file1 &&
437+
test_path_is_missing file2 &&
438+
test_path_is_missing file3 &&
439+
git reset --hard p4/depot/branch4 &&
440+
test_path_is_file file1 &&
441+
test_path_is_missing file2 &&
442+
test_path_is_file file3 &&
443+
git reset --hard p4/depot/branch5 &&
444+
test_path_is_file file1 &&
445+
test_path_is_missing file2 &&
446+
test_path_is_file file3 &&
447+
git reset --hard p4/depot/branch6 &&
448+
test_path_is_file file1 &&
449+
test_path_is_missing file2 &&
450+
test_path_is_missing file3
451+
)
452+
'
453+
414454
# From a report in http://stackoverflow.com/questions/11893688
415455
# where --use-client-spec caused branch prefixes not to be removed;
416456
# every file in git appeared into a subdirectory of the branch name.
@@ -610,4 +650,96 @@ test_expect_success 'Update a file in git side and submit to P4 using client vie
610650
)
611651
'
612652

653+
test_expect_success 'restart p4d (case folding enabled)' '
654+
stop_and_cleanup_p4d &&
655+
start_p4d -C1
656+
'
657+
658+
#
659+
# 1: //depot/main/mf1
660+
# 2: integrate //depot/main/... -> //depot/branch1/...
661+
# 3: //depot/main/mf2
662+
# 4: //depot/BRANCH1/B1f3
663+
# 5: //depot/branch1/b1f4
664+
#
665+
test_expect_success !CASE_INSENSITIVE_FS 'basic p4 branches for case folding' '
666+
(
667+
cd "$cli" &&
668+
mkdir -p main &&
669+
670+
echo mf1 >main/mf1 &&
671+
p4 add main/mf1 &&
672+
p4 submit -d "main/mf1" &&
673+
674+
p4 integrate //depot/main/... //depot/branch1/... &&
675+
p4 submit -d "integrate main to branch1" &&
676+
677+
echo mf2 >main/mf2 &&
678+
p4 add main/mf2 &&
679+
p4 submit -d "main/mf2" &&
680+
681+
mkdir BRANCH1 &&
682+
echo B1f3 >BRANCH1/B1f3 &&
683+
p4 add BRANCH1/B1f3 &&
684+
p4 submit -d "BRANCH1/B1f3" &&
685+
686+
echo b1f4 >branch1/b1f4 &&
687+
p4 add branch1/b1f4 &&
688+
p4 submit -d "branch1/b1f4"
689+
)
690+
'
691+
692+
# Check that files are properly split across branches when ignorecase is set
693+
test_expect_success !CASE_INSENSITIVE_FS 'git p4 clone, branchList branch definition, ignorecase' '
694+
test_when_finished cleanup_git &&
695+
test_create_repo "$git" &&
696+
(
697+
cd "$git" &&
698+
git config git-p4.branchList main:branch1 &&
699+
git config --type=bool core.ignoreCase true &&
700+
git p4 clone --dest=. --detect-branches //depot@all &&
701+
702+
git log --all --graph --decorate --stat &&
703+
704+
git reset --hard p4/master &&
705+
test_path_is_file mf1 &&
706+
test_path_is_file mf2 &&
707+
test_path_is_missing B1f3 &&
708+
test_path_is_missing b1f4 &&
709+
710+
git reset --hard p4/depot/branch1 &&
711+
test_path_is_file mf1 &&
712+
test_path_is_missing mf2 &&
713+
test_path_is_file B1f3 &&
714+
test_path_is_file b1f4
715+
)
716+
'
717+
718+
# Check that files are properly split across branches when ignorecase is set, use-client-spec case
719+
test_expect_success !CASE_INSENSITIVE_FS 'git p4 clone with client-spec, branchList branch definition, ignorecase' '
720+
client_view "//depot/... //client/..." &&
721+
test_when_finished cleanup_git &&
722+
test_create_repo "$git" &&
723+
(
724+
cd "$git" &&
725+
git config git-p4.branchList main:branch1 &&
726+
git config --type=bool core.ignoreCase true &&
727+
git p4 clone --dest=. --use-client-spec --detect-branches //depot@all &&
728+
729+
git log --all --graph --decorate --stat &&
730+
731+
git reset --hard p4/master &&
732+
test_path_is_file mf1 &&
733+
test_path_is_file mf2 &&
734+
test_path_is_missing B1f3 &&
735+
test_path_is_missing b1f4 &&
736+
737+
git reset --hard p4/depot/branch1 &&
738+
test_path_is_file mf1 &&
739+
test_path_is_missing mf2 &&
740+
test_path_is_file B1f3 &&
741+
test_path_is_file b1f4
742+
)
743+
'
744+
613745
test_done

t/t9817-git-p4-exclude.sh

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ test_expect_success 'create exclude repo' '
2222
mkdir -p wanted discard &&
2323
echo wanted >wanted/foo &&
2424
echo discard >discard/foo &&
25-
p4 add wanted/foo discard/foo &&
25+
echo discard_file >discard_file &&
26+
echo discard_file_not >discard_file_not &&
27+
p4 add wanted/foo discard/foo discard_file discard_file_not &&
2628
p4 submit -d "initial revision"
2729
)
2830
'
@@ -33,7 +35,9 @@ test_expect_success 'check the repo was created correctly' '
3335
(
3436
cd "$git" &&
3537
test_path_is_file wanted/foo &&
36-
test_path_is_file discard/foo
38+
test_path_is_file discard/foo &&
39+
test_path_is_file discard_file &&
40+
test_path_is_file discard_file_not
3741
)
3842
'
3943

@@ -43,7 +47,21 @@ test_expect_success 'clone, excluding part of repo' '
4347
(
4448
cd "$git" &&
4549
test_path_is_file wanted/foo &&
46-
test_path_is_missing discard/foo
50+
test_path_is_missing discard/foo &&
51+
test_path_is_file discard_file &&
52+
test_path_is_file discard_file_not
53+
)
54+
'
55+
56+
test_expect_success 'clone, excluding single file, no trailing /' '
57+
test_when_finished cleanup_git &&
58+
git p4 clone -//depot/discard_file --dest="$git" //depot/...@all &&
59+
(
60+
cd "$git" &&
61+
test_path_is_file wanted/foo &&
62+
test_path_is_file discard/foo &&
63+
test_path_is_missing discard_file &&
64+
test_path_is_file discard_file_not
4765
)
4866
'
4967

@@ -52,15 +70,38 @@ test_expect_success 'clone, then sync with exclude' '
5270
git p4 clone -//depot/discard/... --dest="$git" //depot/...@all &&
5371
(
5472
cd "$cli" &&
55-
p4 edit wanted/foo discard/foo &&
73+
p4 edit wanted/foo discard/foo discard_file_not &&
5674
date >>wanted/foo &&
5775
date >>discard/foo &&
76+
date >>discard_file_not &&
5877
p4 submit -d "updating" &&
5978
6079
cd "$git" &&
6180
git p4 sync -//depot/discard/... &&
6281
test_path_is_file wanted/foo &&
63-
test_path_is_missing discard/foo
82+
test_path_is_missing discard/foo &&
83+
test_path_is_file discard_file &&
84+
test_path_is_file discard_file_not
85+
)
86+
'
87+
88+
test_expect_success 'clone, then sync with exclude, no trailing /' '
89+
test_when_finished cleanup_git &&
90+
git p4 clone -//depot/discard/... -//depot/discard_file --dest="$git" //depot/...@all &&
91+
(
92+
cd "$cli" &&
93+
p4 edit wanted/foo discard/foo discard_file_not &&
94+
date >>wanted/foo &&
95+
date >>discard/foo &&
96+
date >>discard_file_not &&
97+
p4 submit -d "updating" &&
98+
99+
cd "$git" &&
100+
git p4 sync -//depot/discard/... -//depot/discard_file &&
101+
test_path_is_file wanted/foo &&
102+
test_path_is_missing discard/foo &&
103+
test_path_is_missing discard_file &&
104+
test_path_is_file discard_file_not
64105
)
65106
'
66107

0 commit comments

Comments
 (0)