Skip to content

Commit 15470c6

Browse files
committed
Merge branch 'pw/p4-various-fixes'
* pw/p4-various-fixes: git p4: remove unneeded cmd initialization git p4: fix labelDetails typo in exception git p4 test: display unresolvable host error git p4: catch p4 errors when streaming file contents git p4: handle servers without move support git p4: catch p4 describe errors
2 parents a4eab8f + 73350fb commit 15470c6

File tree

3 files changed

+137
-20
lines changed

3 files changed

+137
-20
lines changed

git-p4.py

Lines changed: 78 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,25 @@ def p4_has_command(cmd):
129129
p.communicate()
130130
return p.returncode == 0
131131

132+
def p4_has_move_command():
133+
"""See if the move command exists, that it supports -k, and that
134+
it has not been administratively disabled. The arguments
135+
must be correct, but the filenames do not have to exist. Use
136+
ones with wildcards so even if they exist, it will fail."""
137+
138+
if not p4_has_command("move"):
139+
return False
140+
cmd = p4_build_cmd(["move", "-k", "@from", "@to"])
141+
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
142+
(out, err) = p.communicate()
143+
# return code will be 1 in either case
144+
if err.find("Invalid option") >= 0:
145+
return False
146+
if err.find("disabled") >= 0:
147+
return False
148+
# assume it failed because @... was invalid changelist
149+
return True
150+
132151
def system(cmd):
133152
expand = isinstance(cmd,basestring)
134153
if verbose:
@@ -169,6 +188,29 @@ def p4_reopen(type, f):
169188
def p4_move(src, dest):
170189
p4_system(["move", "-k", wildcard_encode(src), wildcard_encode(dest)])
171190

191+
def p4_describe(change):
192+
"""Make sure it returns a valid result by checking for
193+
the presence of field "time". Return a dict of the
194+
results."""
195+
196+
ds = p4CmdList(["describe", "-s", str(change)])
197+
if len(ds) != 1:
198+
die("p4 describe -s %d did not return 1 result: %s" % (change, str(ds)))
199+
200+
d = ds[0]
201+
202+
if "p4ExitCode" in d:
203+
die("p4 describe -s %d exited with %d: %s" % (change, d["p4ExitCode"],
204+
str(d)))
205+
if "code" in d:
206+
if d["code"] == "error":
207+
die("p4 describe -s %d returned error code: %s" % (change, str(d)))
208+
209+
if "time" not in d:
210+
die("p4 describe -s %d returned no \"time\": %s" % (change, str(d)))
211+
212+
return d
213+
172214
#
173215
# Canonicalize the p4 type and return a tuple of the
174216
# base type, plus any modifiers. See "p4 help filetypes"
@@ -871,7 +913,7 @@ def __init__(self):
871913
self.conflict_behavior = None
872914
self.isWindows = (platform.system() == "Windows")
873915
self.exportLabels = False
874-
self.p4HasMoveCommand = p4_has_command("move")
916+
self.p4HasMoveCommand = p4_has_move_command()
875917

876918
def check(self):
877919
if len(p4CmdList("opened ...")) > 0:
@@ -2097,6 +2139,29 @@ def streamOneP4Deletion(self, file):
20972139
# handle another chunk of streaming data
20982140
def streamP4FilesCb(self, marshalled):
20992141

2142+
# catch p4 errors and complain
2143+
err = None
2144+
if "code" in marshalled:
2145+
if marshalled["code"] == "error":
2146+
if "data" in marshalled:
2147+
err = marshalled["data"].rstrip()
2148+
if err:
2149+
f = None
2150+
if self.stream_have_file_info:
2151+
if "depotFile" in self.stream_file:
2152+
f = self.stream_file["depotFile"]
2153+
# force a failure in fast-import, else an empty
2154+
# commit will be made
2155+
self.gitStream.write("\n")
2156+
self.gitStream.write("die-now\n")
2157+
self.gitStream.close()
2158+
# ignore errors, but make sure it exits first
2159+
self.importProcess.wait()
2160+
if f:
2161+
die("Error from p4 print for %s: %s" % (f, err))
2162+
else:
2163+
die("Error from p4 print: %s" % err)
2164+
21002165
if marshalled.has_key('depotFile') and self.stream_have_file_info:
21012166
# start of a new file - output the old one first
21022167
self.streamOneP4File(self.stream_file, self.stream_contents)
@@ -2341,7 +2406,7 @@ def importP4Labels(self, stream, p4Labels):
23412406
try:
23422407
tmwhen = time.strptime(labelDetails['Update'], "%Y/%m/%d %H:%M:%S")
23432408
except ValueError:
2344-
print "Could not convert label time %s" % labelDetail['Update']
2409+
print "Could not convert label time %s" % labelDetails['Update']
23452410
tmwhen = 1
23462411

23472412
when = int(time.mktime(tmwhen))
@@ -2543,7 +2608,7 @@ def searchParent(self, parent, branch, target):
25432608
def importChanges(self, changes):
25442609
cnt = 1
25452610
for change in changes:
2546-
description = p4Cmd(["describe", str(change)])
2611+
description = p4_describe(change)
25472612
self.updateOptionDict(description)
25482613

25492614
if not self.silent:
@@ -2667,14 +2732,8 @@ def importHeadRevision(self, revision):
26672732

26682733
# Use time from top-most change so that all git p4 clones of
26692734
# the same p4 repo have the same commit SHA1s.
2670-
res = p4CmdList("describe -s %d" % newestRevision)
2671-
newestTime = None
2672-
for r in res:
2673-
if r.has_key('time'):
2674-
newestTime = int(r['time'])
2675-
if newestTime is None:
2676-
die("\"describe -s\" on newest change %d did not give a time")
2677-
details["time"] = newestTime
2735+
res = p4_describe(newestRevision)
2736+
details["time"] = res["time"]
26782737

26792738
self.updateOptionDict(details)
26802739
try:
@@ -2864,12 +2923,13 @@ def run(self, args):
28642923

28652924
self.tz = "%+03d%02d" % (- time.timezone / 3600, ((- time.timezone % 3600) / 60))
28662925

2867-
importProcess = subprocess.Popen(["git", "fast-import"],
2868-
stdin=subprocess.PIPE, stdout=subprocess.PIPE,
2869-
stderr=subprocess.PIPE);
2870-
self.gitOutput = importProcess.stdout
2871-
self.gitStream = importProcess.stdin
2872-
self.gitError = importProcess.stderr
2926+
self.importProcess = subprocess.Popen(["git", "fast-import"],
2927+
stdin=subprocess.PIPE,
2928+
stdout=subprocess.PIPE,
2929+
stderr=subprocess.PIPE);
2930+
self.gitOutput = self.importProcess.stdout
2931+
self.gitStream = self.importProcess.stdin
2932+
self.gitError = self.importProcess.stderr
28732933

28742934
if revision:
28752935
self.importHeadRevision(revision)
@@ -2929,7 +2989,7 @@ def run(self, args):
29292989
self.importP4Labels(self.gitStream, missingP4Labels)
29302990

29312991
self.gitStream.close()
2932-
if importProcess.wait() != 0:
2992+
if self.importProcess.wait() != 0:
29332993
die("fast-import failed: %s" % self.gitError.read())
29342994
self.gitOutput.close()
29352995
self.gitError.close()
@@ -3128,7 +3188,6 @@ def main():
31283188
printUsage(commands.keys())
31293189
sys.exit(2)
31303190

3131-
cmd = ""
31323191
cmdName = sys.argv[1]
31333192
try:
31343193
klass = commands[cmdName]

t/t9800-git-p4-basic.sh

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,18 @@ test_expect_success 'exit when p4 fails to produce marshaled output' '
143143
! test_i18ngrep Traceback errs
144144
'
145145

146-
test_expect_success 'clone bare' '
146+
# Hide a file from p4d, make sure we catch its complaint. This won't fail in
147+
# p4 changes, files, or describe; just in p4 print. If P4CLIENT is unset, the
148+
# message will include "Librarian checkout".
149+
test_expect_success 'exit gracefully for p4 server errors' '
150+
test_when_finished "mv \"$db\"/depot/file1,v,hidden \"$db\"/depot/file1,v" &&
151+
mv "$db"/depot/file1,v "$db"/depot/file1,v,hidden &&
152+
test_when_finished cleanup_git &&
153+
test_expect_code 1 git p4 clone --dest="$git" //depot@1 >out 2>err &&
154+
test_i18ngrep "Error from p4 print" err
155+
'
156+
157+
test_expect_success 'clone --bare should make a bare repository' '
147158
rm -rf "$git" &&
148159
git p4 clone --dest="$git" --bare //depot &&
149160
test_when_finished cleanup_git &&
@@ -172,6 +183,18 @@ test_expect_success 'initial import time from top change time' '
172183
)
173184
'
174185

186+
test_expect_success 'unresolvable host in P4PORT should display error' '
187+
test_when_finished cleanup_git &&
188+
git p4 clone --dest="$git" //depot &&
189+
(
190+
cd "$git" &&
191+
P4PORT=nosuchhost:65537 &&
192+
export P4PORT &&
193+
test_expect_code 1 git p4 sync >out 2>err &&
194+
grep "connect to nosuchhost" err
195+
)
196+
'
197+
175198
test_expect_success 'kill p4d' '
176199
kill_p4d
177200
'

t/t9814-git-p4-rename.sh

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,41 @@ test_expect_success 'detect copies' '
199199
)
200200
'
201201

202+
# See if configurables can be set, and in particular if the run.move.allow
203+
# variable exists, which allows admins to disable the "p4 move" command.
204+
test_expect_success 'p4 configure command and run.move.allow are available' '
205+
p4 configure show run.move.allow >out ; retval=$? &&
206+
test $retval = 0 &&
207+
{
208+
egrep ^run.move.allow: out &&
209+
test_set_prereq P4D_HAVE_CONFIGURABLE_RUN_MOVE_ALLOW ||
210+
true
211+
} || true
212+
'
213+
214+
# If move can be disabled, turn it off and test p4 move handling
215+
test_expect_success P4D_HAVE_CONFIGURABLE_RUN_MOVE_ALLOW \
216+
'do not use p4 move when administratively disabled' '
217+
test_when_finished "p4 configure set run.move.allow=1" &&
218+
p4 configure set run.move.allow=0 &&
219+
(
220+
cd "$cli" &&
221+
echo move-disallow-file >move-disallow-file &&
222+
p4 add move-disallow-file &&
223+
p4 submit -d "add move-disallow-file"
224+
) &&
225+
test_when_finished cleanup_git &&
226+
git p4 clone --dest="$git" //depot &&
227+
(
228+
cd "$git" &&
229+
git config git-p4.skipSubmitEdit true &&
230+
git config git-p4.detectRenames true &&
231+
git mv move-disallow-file move-disallow-file-moved &&
232+
git commit -m "move move-disallow-file" &&
233+
git p4 submit
234+
)
235+
'
236+
202237
test_expect_success 'kill p4d' '
203238
kill_p4d
204239
'

0 commit comments

Comments
 (0)