@@ -150,6 +150,21 @@ def decode_text_stream(s):
150
150
def encode_text_stream (s ):
151
151
return s .encode ('utf_8' ) if isinstance (s , unicode ) else s
152
152
153
+ def decode_path (path ):
154
+ """Decode a given string (bytes or otherwise) using configured path encoding options
155
+ """
156
+ encoding = gitConfig ('git-p4.pathEncoding' ) or 'utf_8'
157
+ if bytes is not str :
158
+ return path .decode (encoding , errors = 'replace' ) if isinstance (path , bytes ) else path
159
+ else :
160
+ try :
161
+ path .decode ('ascii' )
162
+ except :
163
+ path = path .decode (encoding , errors = 'replace' )
164
+ if verbose :
165
+ print ('Path with non-ASCII characters detected. Used {} to decode: {}' .format (encoding , path ))
166
+ return path
167
+
153
168
def write_pipe (c , stdin ):
154
169
if verbose :
155
170
sys .stderr .write ('Writing pipe: %s\n ' % str (c ))
@@ -697,7 +712,8 @@ def p4Where(depotPath):
697
712
if "depotFile" in entry :
698
713
# Search for the base client side depot path, as long as it starts with the branch's P4 path.
699
714
# The base path always ends with "/...".
700
- if entry ["depotFile" ].find (depotPath ) == 0 and entry ["depotFile" ][- 4 :] == "/..." :
715
+ entry_path = decode_path (entry ['depotFile' ])
716
+ if entry_path .find (depotPath ) == 0 and entry_path [- 4 :] == "/..." :
701
717
output = entry
702
718
break
703
719
elif "data" in entry :
@@ -712,11 +728,11 @@ def p4Where(depotPath):
712
728
return ""
713
729
clientPath = ""
714
730
if "path" in output :
715
- clientPath = output . get ( " path" )
731
+ clientPath = decode_path ( output [ ' path' ] )
716
732
elif "data" in output :
717
733
data = output .get ("data" )
718
- lastSpace = data .rfind (" " )
719
- clientPath = data [lastSpace + 1 :]
734
+ lastSpace = data .rfind (b " " )
735
+ clientPath = decode_path ( data [lastSpace + 1 :])
720
736
721
737
if clientPath .endswith ("..." ):
722
738
clientPath = clientPath [:- 3 ]
@@ -2484,7 +2500,7 @@ def append(self, view_line):
2484
2500
2485
2501
def convert_client_path (self , clientFile ):
2486
2502
# chop off //client/ part to make it relative
2487
- if not clientFile .startswith (self .client_prefix ):
2503
+ if not decode_path ( clientFile ) .startswith (self .client_prefix ):
2488
2504
die ("No prefix '%s' on clientFile '%s'" %
2489
2505
(self .client_prefix , clientFile ))
2490
2506
return clientFile [len (self .client_prefix ):]
@@ -2493,7 +2509,7 @@ def update_client_spec_path_cache(self, files):
2493
2509
""" Caching file paths by "p4 where" batch query """
2494
2510
2495
2511
# List depot file paths exclude that already cached
2496
- fileArgs = [f ['path' ] for f in files if f ['path' ] not in self .client_spec_path_cache ]
2512
+ fileArgs = [f ['path' ] for f in files if decode_path ( f ['path' ]) not in self .client_spec_path_cache ]
2497
2513
2498
2514
if len (fileArgs ) == 0 :
2499
2515
return # All files in cache
@@ -2508,16 +2524,18 @@ def update_client_spec_path_cache(self, files):
2508
2524
if "unmap" in res :
2509
2525
# it will list all of them, but only one not unmap-ped
2510
2526
continue
2527
+ depot_path = decode_path (res ['depotFile' ])
2511
2528
if gitConfigBool ("core.ignorecase" ):
2512
- res [ 'depotFile' ] = res [ 'depotFile' ] .lower ()
2513
- self .client_spec_path_cache [res [ 'depotFile' ] ] = self .convert_client_path (res ["clientFile" ])
2529
+ depot_path = depot_path .lower ()
2530
+ self .client_spec_path_cache [depot_path ] = self .convert_client_path (res ["clientFile" ])
2514
2531
2515
2532
# not found files or unmap files set to ""
2516
2533
for depotFile in fileArgs :
2534
+ depotFile = decode_path (depotFile )
2517
2535
if gitConfigBool ("core.ignorecase" ):
2518
2536
depotFile = depotFile .lower ()
2519
2537
if depotFile not in self .client_spec_path_cache :
2520
- self .client_spec_path_cache [depotFile ] = ""
2538
+ self .client_spec_path_cache [depotFile ] = b''
2521
2539
2522
2540
def map_in_client (self , depot_path ):
2523
2541
"""Return the relative location in the client where this
@@ -2635,7 +2653,7 @@ def isPathWanted(self, path):
2635
2653
elif path .lower () == p .lower ():
2636
2654
return False
2637
2655
for p in self .depotPaths :
2638
- if p4PathStartsWith (path , p ):
2656
+ if p4PathStartsWith (path , decode_path ( p ) ):
2639
2657
return True
2640
2658
return False
2641
2659
@@ -2644,7 +2662,7 @@ def extractFilesFromCommit(self, commit, shelved=False, shelved_cl = 0):
2644
2662
fnum = 0
2645
2663
while "depotFile%s" % fnum in commit :
2646
2664
path = commit ["depotFile%s" % fnum ]
2647
- found = self .isPathWanted (path )
2665
+ found = self .isPathWanted (decode_path ( path ) )
2648
2666
if not found :
2649
2667
fnum = fnum + 1
2650
2668
continue
@@ -2678,7 +2696,7 @@ def stripRepoPath(self, path, prefixes):
2678
2696
if self .useClientSpec :
2679
2697
# branch detection moves files up a level (the branch name)
2680
2698
# from what client spec interpretation gives
2681
- path = self .clientSpecDirs .map_in_client (path )
2699
+ path = decode_path ( self .clientSpecDirs .map_in_client (path ) )
2682
2700
if self .detectBranches :
2683
2701
for b in self .knownBranches :
2684
2702
if p4PathStartsWith (path , b + "/" ):
@@ -2712,14 +2730,15 @@ def splitFilesIntoBranches(self, commit):
2712
2730
branches = {}
2713
2731
fnum = 0
2714
2732
while "depotFile%s" % fnum in commit :
2715
- path = commit ["depotFile%s" % fnum ]
2733
+ raw_path = commit ["depotFile%s" % fnum ]
2734
+ path = decode_path (raw_path )
2716
2735
found = self .isPathWanted (path )
2717
2736
if not found :
2718
2737
fnum = fnum + 1
2719
2738
continue
2720
2739
2721
2740
file = {}
2722
- file ["path" ] = path
2741
+ file ["path" ] = raw_path
2723
2742
file ["rev" ] = commit ["rev%s" % fnum ]
2724
2743
file ["action" ] = commit ["action%s" % fnum ]
2725
2744
file ["type" ] = commit ["type%s" % fnum ]
@@ -2728,7 +2747,7 @@ def splitFilesIntoBranches(self, commit):
2728
2747
# start with the full relative path where this file would
2729
2748
# go in a p4 client
2730
2749
if self .useClientSpec :
2731
- relPath = self .clientSpecDirs .map_in_client (path )
2750
+ relPath = decode_path ( self .clientSpecDirs .map_in_client (path ) )
2732
2751
else :
2733
2752
relPath = self .stripRepoPath (path , self .depotPaths )
2734
2753
@@ -2766,14 +2785,15 @@ def encodeWithUTF8(self, path):
2766
2785
# - helper for streamP4Files
2767
2786
2768
2787
def streamOneP4File (self , file , contents ):
2769
- relPath = self .stripRepoPath (file ['depotFile' ], self .branchPrefixes )
2770
- relPath = self .encodeWithUTF8 (relPath )
2788
+ file_path = file ['depotFile' ]
2789
+ relPath = self .stripRepoPath (decode_path (file_path ), self .branchPrefixes )
2790
+
2771
2791
if verbose :
2772
2792
if 'fileSize' in self .stream_file :
2773
2793
size = int (self .stream_file ['fileSize' ])
2774
2794
else :
2775
2795
size = 0 # deleted files don't get a fileSize apparently
2776
- sys .stdout .write ('\r %s --> %s (%i MB)\n ' % (file [ 'depotFile' ] , relPath , size / 1024 / 1024 ))
2796
+ sys .stdout .write ('\r %s --> %s (%i MB)\n ' % (file_path , relPath , size / 1024 / 1024 ))
2777
2797
sys .stdout .flush ()
2778
2798
2779
2799
(type_base , type_mods ) = split_p4_type (file ["type" ])
@@ -2791,7 +2811,7 @@ def streamOneP4File(self, file, contents):
2791
2811
# to nothing. This causes p4 errors when checking out such
2792
2812
# a change, and errors here too. Work around it by ignoring
2793
2813
# the bad symlink; hopefully a future change fixes it.
2794
- print ("\n Ignoring empty symlink in %s" % file [ 'depotFile' ] )
2814
+ print ("\n Ignoring empty symlink in %s" % file_path )
2795
2815
return
2796
2816
elif data [- 1 ] == '\n ' :
2797
2817
contents = [data [:- 1 ]]
@@ -2810,15 +2830,15 @@ def streamOneP4File(self, file, contents):
2810
2830
# just the native "NT" type.
2811
2831
#
2812
2832
try :
2813
- text = p4_read_pipe (['print' , '-q' , '-o' , '-' , '%s@%s' % (file ['depotFile' ], file ['change' ])])
2833
+ text = p4_read_pipe (['print' , '-q' , '-o' , '-' , '%s@%s' % (decode_path ( file ['depotFile' ]) , file ['change' ])], raw = True )
2814
2834
except Exception as e :
2815
2835
if 'Translation of file content failed' in str (e ):
2816
2836
type_base = 'binary'
2817
2837
else :
2818
2838
raise e
2819
2839
else :
2820
2840
if p4_version_string ().find ('/NT' ) >= 0 :
2821
- text = text .replace ('\r \n ' , '\n ' )
2841
+ text = text .replace (b '\r \n ' , b '\n ' )
2822
2842
contents = [ text ]
2823
2843
2824
2844
if type_base == "apple" :
@@ -2849,8 +2869,7 @@ def streamOneP4File(self, file, contents):
2849
2869
self .writeToGitStream (git_mode , relPath , contents )
2850
2870
2851
2871
def streamOneP4Deletion (self , file ):
2852
- relPath = self .stripRepoPath (file ['path' ], self .branchPrefixes )
2853
- relPath = self .encodeWithUTF8 (relPath )
2872
+ relPath = self .stripRepoPath (decode_path (file ['path' ]), self .branchPrefixes )
2854
2873
if verbose :
2855
2874
sys .stdout .write ("delete %s\n " % relPath )
2856
2875
sys .stdout .flush ()
@@ -3037,8 +3056,8 @@ def commit(self, details, files, branch, parent = "", allow_empty=False):
3037
3056
if self .clientSpecDirs :
3038
3057
self .clientSpecDirs .update_client_spec_path_cache (files )
3039
3058
3040
- files = [f for f in files
3041
- if self .inClientSpec (f [ ' path' ] ) and self .hasBranchPrefix (f [ ' path' ] )]
3059
+ files = [f for ( f , path ) in (( f , decode_path ( f [ 'path' ])) for f in files )
3060
+ if self .inClientSpec (path ) and self .hasBranchPrefix (path )]
3042
3061
3043
3062
if gitConfigBool ('git-p4.keepEmptyCommits' ):
3044
3063
allow_empty = True
0 commit comments