Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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
  • Loading branch information...
commit 15470c604d7675dbe444165469f76e931a2edc8e 2 parents a4eab8f + 73350fb
Junio C Hamano authored November 29, 2012
97  git-p4.py
@@ -129,6 +129,25 @@ def p4_has_command(cmd):
129 129
     p.communicate()
130 130
     return p.returncode == 0
131 131
 
  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
+
132 151
 def system(cmd):
133 152
     expand = isinstance(cmd,basestring)
134 153
     if verbose:
@@ -169,6 +188,29 @@ def p4_reopen(type, f):
169 188
 def p4_move(src, dest):
170 189
     p4_system(["move", "-k", wildcard_encode(src), wildcard_encode(dest)])
171 190
 
  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
+
172 214
 #
173 215
 # Canonicalize the p4 type and return a tuple of the
174 216
 # base type, plus any modifiers.  See "p4 help filetypes"
@@ -871,7 +913,7 @@ def __init__(self):
871 913
         self.conflict_behavior = None
872 914
         self.isWindows = (platform.system() == "Windows")
873 915
         self.exportLabels = False
874  
-        self.p4HasMoveCommand = p4_has_command("move")
  916
+        self.p4HasMoveCommand = p4_has_move_command()
875 917
 
876 918
     def check(self):
877 919
         if len(p4CmdList("opened ...")) > 0:
@@ -2097,6 +2139,29 @@ def streamOneP4Deletion(self, file):
2097 2139
     # handle another chunk of streaming data
2098 2140
     def streamP4FilesCb(self, marshalled):
2099 2141
 
  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
+
2100 2165
         if marshalled.has_key('depotFile') and self.stream_have_file_info:
2101 2166
             # start of a new file - output the old one first
2102 2167
             self.streamOneP4File(self.stream_file, self.stream_contents)
@@ -2341,7 +2406,7 @@ def importP4Labels(self, stream, p4Labels):
2341 2406
                     try:
2342 2407
                         tmwhen = time.strptime(labelDetails['Update'], "%Y/%m/%d %H:%M:%S")
2343 2408
                     except ValueError:
2344  
-                        print "Could not convert label time %s" % labelDetail['Update']
  2409
+                        print "Could not convert label time %s" % labelDetails['Update']
2345 2410
                         tmwhen = 1
2346 2411
 
2347 2412
                     when = int(time.mktime(tmwhen))
@@ -2543,7 +2608,7 @@ def searchParent(self, parent, branch, target):
2543 2608
     def importChanges(self, changes):
2544 2609
         cnt = 1
2545 2610
         for change in changes:
2546  
-            description = p4Cmd(["describe", str(change)])
  2611
+            description = p4_describe(change)
2547 2612
             self.updateOptionDict(description)
2548 2613
 
2549 2614
             if not self.silent:
@@ -2667,14 +2732,8 @@ def importHeadRevision(self, revision):
2667 2732
 
2668 2733
         # Use time from top-most change so that all git p4 clones of
2669 2734
         # 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"]
2678 2737
 
2679 2738
         self.updateOptionDict(details)
2680 2739
         try:
@@ -2864,12 +2923,13 @@ def run(self, args):
2864 2923
 
2865 2924
         self.tz = "%+03d%02d" % (- time.timezone / 3600, ((- time.timezone % 3600) / 60))
2866 2925
 
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
2873 2933
 
2874 2934
         if revision:
2875 2935
             self.importHeadRevision(revision)
@@ -2929,7 +2989,7 @@ def run(self, args):
2929 2989
             self.importP4Labels(self.gitStream, missingP4Labels)
2930 2990
 
2931 2991
         self.gitStream.close()
2932  
-        if importProcess.wait() != 0:
  2992
+        if self.importProcess.wait() != 0:
2933 2993
             die("fast-import failed: %s" % self.gitError.read())
2934 2994
         self.gitOutput.close()
2935 2995
         self.gitError.close()
@@ -3128,7 +3188,6 @@ def main():
3128 3188
         printUsage(commands.keys())
3129 3189
         sys.exit(2)
3130 3190
 
3131  
-    cmd = ""
3132 3191
     cmdName = sys.argv[1]
3133 3192
     try:
3134 3193
         klass = commands[cmdName]
25  t/t9800-git-p4-basic.sh
@@ -143,7 +143,18 @@ test_expect_success 'exit when p4 fails to produce marshaled output' '
143 143
 	! test_i18ngrep Traceback errs
144 144
 '
145 145
 
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' '
147 158
 	rm -rf "$git" &&
148 159
 	git p4 clone --dest="$git" --bare //depot &&
149 160
 	test_when_finished cleanup_git &&
@@ -172,6 +183,18 @@ test_expect_success 'initial import time from top change time' '
172 183
 	)
173 184
 '
174 185
 
  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
+
175 198
 test_expect_success 'kill p4d' '
176 199
 	kill_p4d
177 200
 '
35  t/t9814-git-p4-rename.sh
@@ -199,6 +199,41 @@ test_expect_success 'detect copies' '
199 199
 	)
200 200
 '
201 201
 
  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
+
202 237
 test_expect_success 'kill p4d' '
203 238
 	kill_p4d
204 239
 '

0 notes on commit 15470c6

Please sign in to comment.
Something went wrong with that request. Please try again.