git-p4: refactoring of p4CmdList()
The function p4CmdList executes a Perforce command and decodes the marshalled python dictionary. Special care has to be taken for certain dictionary values which contain non-unicode characters. The old handling contained separate hacks for each of the corresponding dictionary keys. This commit tries to refactor the coding to handle the special cases uniformely. Signed-off-by: Kilian Kilger <kkilger@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Kilian Kilger committed
Jul 21, 2022 at 09:07 UTC
d205483695366803e912da6ae24380c33c293467
1 file changed
+42
-11
git-p4.py
+42
-11
@@ -822,6 +822,42 @@ def isModeExecChanged(src_mode, dst_mode):
822
return isModeExec(src_mode) != isModeExec(dst_mode)
823
824
825
+def p4KeysContainingNonUtf8Chars():
826
+ """Returns all keys which may contain non UTF-8 encoded strings
827
+ for which a fallback strategy has to be applied.
828
+ """
829
+ return ['desc', 'client', 'FullName']
830
+
831
+
832
+def p4KeysContainingBinaryData():
833
+ """Returns all keys which may contain arbitrary binary data
834
+ """
835
+ return ['data']
836
+
837
+
838
+def p4KeyContainsFilePaths(key):
839
+ """Returns True if the key contains file paths. These are handled by decode_path().
840
+ Otherwise False.
841
+ """
842
+ return key.startswith('depotFile') or key in ['path', 'clientFile']
843
+
844
+
845
+def p4KeyWhichCanBeDirectlyDecoded(key):
846
+ """Returns True if the key can be directly decoded as UTF-8 string
847
+ Otherwise False.
848
+
849
+ Keys which can not be encoded directly:
850
+ - `data` which may contain arbitrary binary data
851
+ - `desc` or `client` or `FullName` which may contain non-UTF8 encoded text
852
+ - `depotFile[0-9]*`, `path`, or `clientFile` which may contain non-UTF8 encoded text, handled by decode_path()
853
+ """
854
+ if key in p4KeysContainingNonUtf8Chars() or \
855
+ key in p4KeysContainingBinaryData() or \
856
+ p4KeyContainsFilePaths(key):
857
+ return False
858
+ return True
859
+
860
+
861
def p4CmdList(cmd, stdin=None, stdin_mode='w+b', cb=None, skip_info=False,
862
errors_as_exceptions=False, *k, **kw):
863
@@ -851,15 +887,13 @@ def p4CmdList(cmd, stdin=None, stdin_mode='w+b', cb=None, skip_info=False,
887
try:
888
while True:
889
entry = marshal.load(p4.stdout)
890
+
891
if bytes is not str:
855
- # Decode unmarshalled dict to use str keys and values, except for:
856
- # - `data` which may contain arbitrary binary data
857
- # - `desc` or `client` or `FullName` which may contain non-UTF8 encoded text handled below, eagerly converted to bytes
858
- # - `depotFile[0-9]*`, `path`, or `clientFile` which may contain non-UTF8 encoded text, handled by decode_path()
892
+ # Decode unmarshalled dict to use str keys and values. Special cases are handled below.
893
decoded_entry = {}
894
for key, value in entry.items():
895
key = key.decode()
862
- if isinstance(value, bytes) and not (key in ('data', 'desc', 'FullName', 'path', 'clientFile', 'client') or key.startswith('depotFile')):
896
+ if isinstance(value, bytes) and p4KeyWhichCanBeDirectlyDecoded(key):
897
value = value.decode()
898
decoded_entry[key] = value
899
# Parse out data if it's an error response
@@ -869,12 +903,9 @@ def p4CmdList(cmd, stdin=None, stdin_mode='w+b', cb=None, skip_info=False,
903
if skip_info:
904
if 'code' in entry and entry['code'] == 'info':
905
continue
872
- if 'desc' in entry:
873
- entry['desc'] = metadata_stream_to_writable_bytes(entry['desc'])
874
- if 'client' in entry:
875
- entry['client'] = metadata_stream_to_writable_bytes(entry['client'])
876
- if 'FullName' in entry:
877
- entry['FullName'] = metadata_stream_to_writable_bytes(entry['FullName'])
906
+ for key in p4KeysContainingNonUtf8Chars():
907
+ if key in entry:
908
+ entry[key] = metadata_stream_to_writable_bytes(entry[key])
909
if cb is not None:
910
cb(entry)
911
else: