git-p4: better error reporting when p4 fails

Currently when p4 fails to run, git-p4 just crashes with an obscure error message. For example, if the P4 ticket has expired, you get: Error: Cannot locate perforce checkout of <path> in client view This change checks whether git-p4 can talk to the Perforce server when the first P4 operation is attempted, and tries to print a meaningful error message if it fails. Signed-off-by: Luke Diamand <luke@diamand.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Luke Diamand committed Jun 8, 2018 at 21:32 UTC 0ef67acdd784852ee8e86dcdb653cc290c1a77a3
2 files changed +133
git-p4.py
+55
@@ -50,6 +50,8 @@ defaultLabelRegexp = r'[a-zA-Z0-9_\-.]+$'
50 # Grab changes in blocks of this many revisions, unless otherwise requested
51 defaultBlockSize = 512
52
53 +p4_access_checked = False
54 +
55 def p4_build_cmd(cmd):
56 """Build a suitable p4 command line.
57
@@ -91,6 +93,13 @@ def p4_build_cmd(cmd):
93 real_cmd = ' '.join(real_cmd) + ' ' + cmd
94 else:
95 real_cmd += cmd
96 +
97 + # now check that we can actually talk to the server
98 + global p4_access_checked
99 + if not p4_access_checked:
100 + p4_access_checked = True # suppress access checks in p4_check_access itself
101 + p4_check_access()
102 +
103 return real_cmd
104
105 def git_dir(path):
@@ -264,6 +273,52 @@ def p4_system(cmd):
273 if retcode:
274 raise CalledProcessError(retcode, real_cmd)
275
276 +def die_bad_access(s):
277 + die("failure accessing depot: {0}".format(s.rstrip()))
278 +
279 +def p4_check_access(min_expiration=1):
280 + """ Check if we can access Perforce - account still logged in
281 + """
282 + results = p4CmdList(["login", "-s"])
283 +
284 + if len(results) == 0:
285 + # should never get here: always get either some results, or a p4ExitCode
286 + assert("could not parse response from perforce")
287 +
288 + result = results[0]
289 +
290 + if 'p4ExitCode' in result:
291 + # p4 returned non-zero status, e.g. P4PORT invalid, or p4 not in path
292 + die_bad_access("could not run p4")
293 +
294 + code = result.get("code")
295 + if not code:
296 + # we get here if we couldn't connect and there was nothing to unmarshal
297 + die_bad_access("could not connect")
298 +
299 + elif code == "stat":
300 + expiry = result.get("TicketExpiration")
301 + if expiry:
302 + expiry = int(expiry)
303 + if expiry > min_expiration:
304 + # ok to carry on
305 + return
306 + else:
307 + die_bad_access("perforce ticket expires in {0} seconds".format(expiry))
308 +
309 + else:
310 + # account without a timeout - all ok
311 + return
312 +
313 + elif code == "error":
314 + data = result.get("data")
315 + if data:
316 + die_bad_access("p4 error: {0}".format(data))
317 + else:
318 + die_bad_access("unknown error")
319 + else:
320 + die_bad_access("unknown error code {0}".format(code))
321 +
322 _p4_version_string = None
323 def p4_version_string():
324 """Read the version string, showing just the last line, which
t/t9833-errors.sh new
+78
@@ -0,0 +1,78 @@
1 +#!/bin/sh
2 +
3 +test_description='git p4 errors'
4 +
5 +. ./lib-git-p4.sh
6 +
7 +test_expect_success 'start p4d' '
8 + start_p4d
9 +'
10 +
11 +test_expect_success 'add p4 files' '
12 + (
13 + cd "$cli" &&
14 + echo file1 >file1 &&
15 + p4 add file1 &&
16 + p4 submit -d "file1"
17 + )
18 +'
19 +
20 +# after this test, the default user requires a password
21 +test_expect_success 'error handling' '
22 + git p4 clone --dest="$git" //depot@all &&
23 + (
24 + cd "$git" &&
25 + P4PORT=: test_must_fail git p4 submit 2>errmsg
26 + ) &&
27 + p4 passwd -P newpassword &&
28 + (
29 + P4PASSWD=badpassword test_must_fail git p4 clone //depot/foo 2>errmsg &&
30 + grep -q "failure accessing depot.*P4PASSWD" errmsg
31 + )
32 +'
33 +
34 +test_expect_success 'ticket logged out' '
35 + P4TICKETS="$cli/tickets" &&
36 + echo "newpassword" | p4 login &&
37 + (
38 + cd "$git" &&
39 + test_commit "ticket-auth-check" &&
40 + p4 logout &&
41 + test_must_fail git p4 submit 2>errmsg &&
42 + grep -q "failure accessing depot" errmsg
43 + )
44 +'
45 +
46 +test_expect_success 'create group with short ticket expiry' '
47 + P4TICKETS="$cli/tickets" &&
48 + echo "newpassword" | p4 login &&
49 + p4_add_user short_expiry_user &&
50 + p4 -u short_expiry_user passwd -P password &&
51 + p4 group -i <<-EOF &&
52 + Group: testgroup
53 + Timeout: 3
54 + Users: short_expiry_user
55 + EOF
56 +
57 + p4 users | grep short_expiry_user
58 +'
59 +
60 +test_expect_success 'git operation with expired ticket' '
61 + P4TICKETS="$cli/tickets" &&
62 + P4USER=short_expiry_user &&
63 + echo "password" | p4 login &&
64 + (
65 + cd "$git" &&
66 + git p4 sync &&
67 + sleep 5 &&
68 + test_must_fail git p4 sync 2>errmsg &&
69 + grep "failure accessing depot" errmsg
70 + )
71 +'
72 +
73 +test_expect_success 'kill p4d' '
74 + kill_p4d
75 +'
76 +
77 +
78 +test_done