Skip to content

Commit 8d3a362

Browse files
committed
Merge branch 'pw/p4'
* pw/p4: git-p4: support clone --bare git-p4: decode p4 wildcard characters git-p4: better message for "git-p4 sync" when not cloned git-p4: reinterpret confusing p4 message git-p4: accommodate new move/delete type in p4 git-p4: add missing newline in initial import message git-p4: fix key error for p4 problem git-p4: test script
2 parents c0791f3 + 3820007 commit 8d3a362

File tree

2 files changed

+149
-11
lines changed

2 files changed

+149
-11
lines changed

contrib/fast-import/git-p4

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -834,6 +834,8 @@ class P4Submit(Command):
834834
return True
835835

836836
class P4Sync(Command):
837+
delete_actions = ( "delete", "move/delete", "purge" )
838+
837839
def __init__(self):
838840
Command.__init__(self)
839841
self.options = [
@@ -882,6 +884,23 @@ class P4Sync(Command):
882884
if gitConfig("git-p4.syncFromOrigin") == "false":
883885
self.syncWithOrigin = False
884886

887+
#
888+
# P4 wildcards are not allowed in filenames. P4 complains
889+
# if you simply add them, but you can force it with "-f", in
890+
# which case it translates them into %xx encoding internally.
891+
# Search for and fix just these four characters. Do % last so
892+
# that fixing it does not inadvertently create new %-escapes.
893+
#
894+
def wildcard_decode(self, path):
895+
# Cannot have * in a filename in windows; untested as to
896+
# what p4 would do in such a case.
897+
if not self.isWindows:
898+
path = path.replace("%2A", "*")
899+
path = path.replace("%23", "#") \
900+
.replace("%40", "@") \
901+
.replace("%25", "%")
902+
return path
903+
885904
def extractFilesFromCommit(self, commit):
886905
self.cloneExclude = [re.sub(r"\.\.\.$", "", path)
887906
for path in self.cloneExclude]
@@ -976,6 +995,7 @@ class P4Sync(Command):
976995
return
977996

978997
relPath = self.stripRepoPath(file['depotFile'], self.branchPrefixes)
998+
relPath = self.wildcard_decode(relPath)
979999
if verbose:
9801000
sys.stderr.write("%s\n" % relPath)
9811001

@@ -1054,10 +1074,10 @@ class P4Sync(Command):
10541074

10551075
if includeFile:
10561076
filesForCommit.append(f)
1057-
if f['action'] not in ('delete', 'move/delete', 'purge'):
1058-
filesToRead.append(f)
1059-
else:
1077+
if f['action'] in self.delete_actions:
10601078
filesToDelete.append(f)
1079+
else:
1080+
filesToRead.append(f)
10611081

10621082
# deleted files...
10631083
for f in filesToDelete:
@@ -1143,7 +1163,7 @@ class P4Sync(Command):
11431163

11441164
cleanedFiles = {}
11451165
for info in files:
1146-
if info["action"] in ("delete", "purge"):
1166+
if info["action"] in self.delete_actions:
11471167
continue
11481168
cleanedFiles[info["depotFile"]] = info["rev"]
11491169

@@ -1445,7 +1465,7 @@ class P4Sync(Command):
14451465
print "Doing initial import of %s from revision %s into %s" % (' '.join(self.depotPaths), revision, self.branch)
14461466

14471467
details = { "user" : "git perforce import user", "time" : int(time.time()) }
1448-
details["desc"] = ("Initial import of %s from the state at revision %s"
1468+
details["desc"] = ("Initial import of %s from the state at revision %s\n"
14491469
% (' '.join(self.depotPaths), revision))
14501470
details["change"] = revision
14511471
newestRevision = 0
@@ -1456,17 +1476,24 @@ class P4Sync(Command):
14561476
% (p, revision)
14571477
for p in self.depotPaths])):
14581478

1459-
if info['code'] == 'error':
1479+
if 'code' in info and info['code'] == 'error':
14601480
sys.stderr.write("p4 returned an error: %s\n"
14611481
% info['data'])
1482+
if info['data'].find("must refer to client") >= 0:
1483+
sys.stderr.write("This particular p4 error is misleading.\n")
1484+
sys.stderr.write("Perhaps the depot path was misspelled.\n");
1485+
sys.stderr.write("Depot path: %s\n" % " ".join(self.depotPaths))
1486+
sys.exit(1)
1487+
if 'p4ExitCode' in info:
1488+
sys.stderr.write("p4 exitcode: %s\n" % info['p4ExitCode'])
14621489
sys.exit(1)
14631490

14641491

14651492
change = int(info["change"])
14661493
if change > newestRevision:
14671494
newestRevision = change
14681495

1469-
if info["action"] in ("delete", "purge"):
1496+
if info["action"] in self.delete_actions:
14701497
# don't increase the file cnt, otherwise details["depotFile123"] will have gaps!
14711498
#fileCnt = fileCnt + 1
14721499
continue
@@ -1709,6 +1736,8 @@ class P4Sync(Command):
17091736

17101737
changes.sort()
17111738
else:
1739+
if not self.p4BranchesInGit:
1740+
die("No remote p4 branches. Perhaps you never did \"git p4 clone\" in here.");
17121741
if self.verbose:
17131742
print "Getting p4 changes for %s...%s" % (', '.join(self.depotPaths),
17141743
self.changeRange)
@@ -1789,10 +1818,13 @@ class P4Clone(P4Sync):
17891818
help="where to leave result of the clone"),
17901819
optparse.make_option("-/", dest="cloneExclude",
17911820
action="append", type="string",
1792-
help="exclude depot path")
1821+
help="exclude depot path"),
1822+
optparse.make_option("--bare", dest="cloneBare",
1823+
action="store_true", default=False),
17931824
]
17941825
self.cloneDestination = None
17951826
self.needsGit = False
1827+
self.cloneBare = False
17961828

17971829
# This is required for the "append" cloneExclude action
17981830
def ensure_value(self, attr, value):
@@ -1832,11 +1864,16 @@ class P4Clone(P4Sync):
18321864
self.cloneDestination = self.defaultDestination(args)
18331865

18341866
print "Importing from %s into %s" % (', '.join(depotPaths), self.cloneDestination)
1867+
18351868
if not os.path.exists(self.cloneDestination):
18361869
os.makedirs(self.cloneDestination)
18371870
chdir(self.cloneDestination)
1838-
system("git init")
1839-
self.gitdir = os.getcwd() + "/.git"
1871+
1872+
init_cmd = [ "git", "init" ]
1873+
if self.cloneBare:
1874+
init_cmd.append("--bare")
1875+
subprocess.check_call(init_cmd)
1876+
18401877
if not P4Sync.run(self, depotPaths):
18411878
return False
18421879
if self.branch != "master":
@@ -1846,7 +1883,8 @@ class P4Clone(P4Sync):
18461883
masterbranch = "refs/heads/p4/master"
18471884
if gitBranchExists(masterbranch):
18481885
system("git branch master %s" % masterbranch)
1849-
system("git checkout -f")
1886+
if not self.cloneBare:
1887+
system("git checkout -f")
18501888
else:
18511889
print "Could not detect main branch. No checkout/master branch created."
18521890

t/t9800-git-p4.sh

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
#!/bin/sh
2+
3+
test_description='git-p4 tests'
4+
5+
. ./test-lib.sh
6+
7+
( p4 -h && p4d -h ) >/dev/null 2>&1 || {
8+
skip_all='skipping git-p4 tests; no p4 or p4d'
9+
test_done
10+
}
11+
12+
GITP4=$GIT_BUILD_DIR/contrib/fast-import/git-p4
13+
P4DPORT=10669
14+
15+
db="$TRASH_DIRECTORY/db"
16+
cli="$TRASH_DIRECTORY/cli"
17+
git="$TRASH_DIRECTORY/git"
18+
19+
test_debug 'echo p4d -q -d -r "$db" -p $P4DPORT'
20+
test_expect_success setup '
21+
mkdir -p "$db" &&
22+
p4d -q -d -r "$db" -p $P4DPORT &&
23+
mkdir -p "$cli" &&
24+
mkdir -p "$git" &&
25+
export P4PORT=localhost:$P4DPORT
26+
'
27+
28+
test_expect_success 'add p4 files' '
29+
cd "$cli" &&
30+
p4 client -i <<-EOF &&
31+
Client: client
32+
Description: client
33+
Root: $cli
34+
View: //depot/... //client/...
35+
EOF
36+
export P4CLIENT=client &&
37+
echo file1 >file1 &&
38+
p4 add file1 &&
39+
p4 submit -d "file1" &&
40+
cd "$TRASH_DIRECTORY"
41+
'
42+
43+
test_expect_success 'basic git-p4 clone' '
44+
"$GITP4" clone --dest="$git" //depot &&
45+
rm -rf "$git" && mkdir "$git"
46+
'
47+
48+
test_expect_success 'exit when p4 fails to produce marshaled output' '
49+
badp4dir="$TRASH_DIRECTORY/badp4dir" &&
50+
mkdir -p "$badp4dir" &&
51+
cat >"$badp4dir"/p4 <<-EOF &&
52+
#!$SHELL_PATH
53+
exit 1
54+
EOF
55+
chmod 755 "$badp4dir"/p4 &&
56+
PATH="$badp4dir:$PATH" "$GITP4" clone --dest="$git" //depot >errs 2>&1 ; retval=$? &&
57+
test $retval -eq 1 &&
58+
test_must_fail grep -q Traceback errs
59+
'
60+
61+
test_expect_success 'add p4 files with wildcards in the names' '
62+
cd "$cli" &&
63+
echo file-wild-hash >file-wild#hash &&
64+
echo file-wild-star >file-wild\*star &&
65+
echo file-wild-at >file-wild@at &&
66+
echo file-wild-percent >file-wild%percent &&
67+
p4 add -f file-wild* &&
68+
p4 submit -d "file wildcards" &&
69+
cd "$TRASH_DIRECTORY"
70+
'
71+
72+
test_expect_success 'wildcard files git-p4 clone' '
73+
"$GITP4" clone --dest="$git" //depot &&
74+
cd "$git" &&
75+
test -f file-wild#hash &&
76+
test -f file-wild\*star &&
77+
test -f file-wild@at &&
78+
test -f file-wild%percent &&
79+
cd "$TRASH_DIRECTORY" &&
80+
rm -rf "$git" && mkdir "$git"
81+
'
82+
83+
test_expect_success 'clone bare' '
84+
"$GITP4" clone --dest="$git" --bare //depot &&
85+
cd "$git" &&
86+
test ! -d .git &&
87+
bare=`git config --get core.bare` &&
88+
test "$bare" = true &&
89+
cd "$TRASH_DIRECTORY" &&
90+
rm -rf "$git" && mkdir "$git"
91+
'
92+
93+
test_expect_success 'shutdown' '
94+
pid=`pgrep -f p4d` &&
95+
test -n "$pid" &&
96+
test_debug "ps wl `echo $pid`" &&
97+
kill $pid
98+
'
99+
100+
test_done

0 commit comments

Comments
 (0)