@@ -133,25 +133,29 @@ def p4_system(cmd):
133
133
subprocess .check_call (real_cmd , shell = expand )
134
134
135
135
def p4_integrate (src , dest ):
136
- p4_system (["integrate" , "-Dt" , src , dest ])
136
+ p4_system (["integrate" , "-Dt" , wildcard_encode ( src ), wildcard_encode ( dest ) ])
137
137
138
- def p4_sync (path ):
139
- p4_system (["sync" , path ])
138
+ def p4_sync (f , * options ):
139
+ p4_system (["sync" ] + list ( options ) + [ wildcard_encode ( f ) ])
140
140
141
141
def p4_add (f ):
142
- p4_system (["add" , f ])
142
+ # forcibly add file names with wildcards
143
+ if wildcard_present (f ):
144
+ p4_system (["add" , "-f" , f ])
145
+ else :
146
+ p4_system (["add" , f ])
143
147
144
148
def p4_delete (f ):
145
- p4_system (["delete" , f ])
149
+ p4_system (["delete" , wildcard_encode ( f ) ])
146
150
147
151
def p4_edit (f ):
148
- p4_system (["edit" , f ])
152
+ p4_system (["edit" , wildcard_encode ( f ) ])
149
153
150
154
def p4_revert (f ):
151
- p4_system (["revert" , f ])
155
+ p4_system (["revert" , wildcard_encode ( f ) ])
152
156
153
- def p4_reopen (type , file ):
154
- p4_system (["reopen" , "-t" , type , file ])
157
+ def p4_reopen (type , f ):
158
+ p4_system (["reopen" , "-t" , type , wildcard_encode ( f ) ])
155
159
156
160
#
157
161
# Canonicalize the p4 type and return a tuple of the
@@ -248,7 +252,7 @@ def setP4ExecBit(file, mode):
248
252
def getP4OpenedType (file ):
249
253
# Returns the perforce file type for the given file.
250
254
251
- result = p4_read_pipe (["opened" , file ])
255
+ result = p4_read_pipe (["opened" , wildcard_encode ( file ) ])
252
256
match = re .match (".*\((.+)\)\r ?$" , result )
253
257
if match :
254
258
return match .group (1 )
@@ -658,6 +662,34 @@ def getClientRoot():
658
662
659
663
return entry ["Root" ]
660
664
665
+ #
666
+ # P4 wildcards are not allowed in filenames. P4 complains
667
+ # if you simply add them, but you can force it with "-f", in
668
+ # which case it translates them into %xx encoding internally.
669
+ #
670
+ def wildcard_decode (path ):
671
+ # Search for and fix just these four characters. Do % last so
672
+ # that fixing it does not inadvertently create new %-escapes.
673
+ # Cannot have * in a filename in windows; untested as to
674
+ # what p4 would do in such a case.
675
+ if not platform .system () == "Windows" :
676
+ path = path .replace ("%2A" , "*" )
677
+ path = path .replace ("%23" , "#" ) \
678
+ .replace ("%40" , "@" ) \
679
+ .replace ("%25" , "%" )
680
+ return path
681
+
682
+ def wildcard_encode (path ):
683
+ # do % first to avoid double-encoding the %s introduced here
684
+ path = path .replace ("%" , "%25" ) \
685
+ .replace ("*" , "%2A" ) \
686
+ .replace ("#" , "%23" ) \
687
+ .replace ("@" , "%40" )
688
+ return path
689
+
690
+ def wildcard_present (path ):
691
+ return path .translate (None , "*#@%" ) != path
692
+
661
693
class Command :
662
694
def __init__ (self ):
663
695
self .usage = "usage: %prog [options]"
@@ -1038,6 +1070,7 @@ def applyCommit(self, id):
1038
1070
filesToAdd = set ()
1039
1071
filesToDelete = set ()
1040
1072
editedFiles = set ()
1073
+ pureRenameCopy = set ()
1041
1074
filesToChangeExecBit = {}
1042
1075
1043
1076
for line in diff :
@@ -1061,10 +1094,13 @@ def applyCommit(self, id):
1061
1094
elif modifier == "C" :
1062
1095
src , dest = diff ['src' ], diff ['dst' ]
1063
1096
p4_integrate (src , dest )
1097
+ pureRenameCopy .add (dest )
1064
1098
if diff ['src_sha1' ] != diff ['dst_sha1' ]:
1065
1099
p4_edit (dest )
1100
+ pureRenameCopy .discard (dest )
1066
1101
if isModeExecChanged (diff ['src_mode' ], diff ['dst_mode' ]):
1067
1102
p4_edit (dest )
1103
+ pureRenameCopy .discard (dest )
1068
1104
filesToChangeExecBit [dest ] = diff ['dst_mode' ]
1069
1105
os .unlink (dest )
1070
1106
editedFiles .add (dest )
@@ -1073,6 +1109,8 @@ def applyCommit(self, id):
1073
1109
p4_integrate (src , dest )
1074
1110
if diff ['src_sha1' ] != diff ['dst_sha1' ]:
1075
1111
p4_edit (dest )
1112
+ else :
1113
+ pureRenameCopy .add (dest )
1076
1114
if isModeExecChanged (diff ['src_mode' ], diff ['dst_mode' ]):
1077
1115
p4_edit (dest )
1078
1116
filesToChangeExecBit [dest ] = diff ['dst_mode' ]
@@ -1181,7 +1219,8 @@ def applyCommit(self, id):
1181
1219
del (os .environ ["P4DIFF" ])
1182
1220
diff = ""
1183
1221
for editedFile in editedFiles :
1184
- diff += p4_read_pipe (['diff' , '-du' , editedFile ])
1222
+ diff += p4_read_pipe (['diff' , '-du' ,
1223
+ wildcard_encode (editedFile )])
1185
1224
1186
1225
newdiff = ""
1187
1226
for newFile in filesToAdd :
@@ -1226,6 +1265,12 @@ def applyCommit(self, id):
1226
1265
# unmarshalled.
1227
1266
changelist = self .lastP4Changelist ()
1228
1267
self .modifyChangelistUser (changelist , p4User )
1268
+
1269
+ # The rename/copy happened by applying a patch that created a
1270
+ # new file. This leaves it writable, which confuses p4.
1271
+ for f in pureRenameCopy :
1272
+ p4_sync (f , "-f" )
1273
+
1229
1274
else :
1230
1275
# skip this patch
1231
1276
print "Submission cancelled, undoing p4 changes."
@@ -1361,12 +1406,18 @@ def run(self, args):
1361
1406
self .oldWorkingDirectory = os .getcwd ()
1362
1407
1363
1408
# ensure the clientPath exists
1409
+ new_client_dir = False
1364
1410
if not os .path .exists (self .clientPath ):
1411
+ new_client_dir = True
1365
1412
os .makedirs (self .clientPath )
1366
1413
1367
1414
chdir (self .clientPath )
1368
1415
print "Synchronizing p4 checkout..."
1369
- p4_sync ("..." )
1416
+ if new_client_dir :
1417
+ # old one was destroyed, and maybe nobody told p4
1418
+ p4_sync ("..." , "-f" )
1419
+ else :
1420
+ p4_sync ("..." )
1370
1421
self .check ()
1371
1422
1372
1423
commits = []
@@ -1679,23 +1730,6 @@ def __init__(self):
1679
1730
if gitConfig ("git-p4.syncFromOrigin" ) == "false" :
1680
1731
self .syncWithOrigin = False
1681
1732
1682
- #
1683
- # P4 wildcards are not allowed in filenames. P4 complains
1684
- # if you simply add them, but you can force it with "-f", in
1685
- # which case it translates them into %xx encoding internally.
1686
- # Search for and fix just these four characters. Do % last so
1687
- # that fixing it does not inadvertently create new %-escapes.
1688
- #
1689
- def wildcard_decode (self , path ):
1690
- # Cannot have * in a filename in windows; untested as to
1691
- # what p4 would do in such a case.
1692
- if not self .isWindows :
1693
- path = path .replace ("%2A" , "*" )
1694
- path = path .replace ("%23" , "#" ) \
1695
- .replace ("%40" , "@" ) \
1696
- .replace ("%25" , "%" )
1697
- return path
1698
-
1699
1733
# Force a checkpoint in fast-import and wait for it to finish
1700
1734
def checkpoint (self ):
1701
1735
self .gitStream .write ("checkpoint\n \n " )
@@ -1763,6 +1797,7 @@ def splitFilesIntoBranches(self, commit):
1763
1797
fnum = fnum + 1
1764
1798
1765
1799
relPath = self .stripRepoPath (path , self .depotPaths )
1800
+ relPath = wildcard_decode (relPath )
1766
1801
1767
1802
for branch in self .knownBranches .keys ():
1768
1803
@@ -1780,7 +1815,7 @@ def splitFilesIntoBranches(self, commit):
1780
1815
1781
1816
def streamOneP4File (self , file , contents ):
1782
1817
relPath = self .stripRepoPath (file ['depotFile' ], self .branchPrefixes )
1783
- relPath = self . wildcard_decode (relPath )
1818
+ relPath = wildcard_decode (relPath )
1784
1819
if verbose :
1785
1820
sys .stderr .write ("%s\n " % relPath )
1786
1821
@@ -1849,6 +1884,7 @@ def streamOneP4File(self, file, contents):
1849
1884
1850
1885
def streamOneP4Deletion (self , file ):
1851
1886
relPath = self .stripRepoPath (file ['path' ], self .branchPrefixes )
1887
+ relPath = wildcard_decode (relPath )
1852
1888
if verbose :
1853
1889
sys .stderr .write ("delete %s\n " % relPath )
1854
1890
self .gitStream .write ("D %s\n " % relPath )
0 commit comments