git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v5 12/15] git-p4: p4CmdList - support Unicode encoding

From
Ben Keene via GitGitGadget <gitgitgadget@gmail.com>
Date
Dec 7, 2019, 17:47 UTC
Message-ID
<e97ac0af8a33bc55c32b96d76136aef106d7b337.1575740863.git.gitgitgadget@gmail.com>
In-Reply-To
<pull.463.v5.git.1575740863.gitgitgadget@gmail.com>
From: Ben Keene <seraphire@gmail.com>

The p4CmdList is a commonly used function in the git-p4 code. It is used to execute a command in P4 and return the results of the call in a list.

The problem is that p4CmdList takes bytes as the parameter data and returns bytes in the return list.

Add a new optional parameter to the signature, encode_cmd_output, that determines if the dictionary values returned in the function output are treated as bytes or as strings.

Change the code to conditionally pass the output data through the as_string() function when encode_cmd_output is true. Otherwise the function should return the data as bytes.

Change the code so that regardless of the setting of encode_cmd_output, the dictionary keys in the return value will always be encoded with as_string().

as_string(bytes) is a method defined in this project that treats the byte data as a string. The word "string" is used because the meaning varies depending on the version of Python:

  - Python 2: The "bytes" are returned as "str", functionally a No-op.
  - Python 3: The "bytes" are returned as a Unicode string.

The p4CmdList function returns a list of dictionaries that contain the result of p4 command. If the callback (cb) is defined, the standard output of the p4 command is redirected.

Data that is passed to the standard input of the P4 process should be as_bytes() to avoid conversion unicode encoding errors.

as_bytes(text) is a method defined in this project that treats the text data as a string that should be converted to a byte array (bytes). The behavior of this function depends on the version of python:

  - Python 2: The "text" is returned as "str", functionally a No-op.
  - Python 3: The "text" is treated as a UTF-8 encoded Unicode string
        and is decoded to bytes.

Additionally, change literal text prior to conversion to be literal bytes for the code that is evaluating the standard output from the p4 call.

Add encode_cmd_output to the p4Cmd since this is a helper function that wraps the behavior of p4CmdList.

Signed-off-by: Ben Keene <seraphire@gmail.com>
---
 git-p4.py | 36 ++++++++++++++++++++++++++++--------
 1 file changed, 28 insertions(+), 8 deletions(-)
diff --git a/git-p4.py b/git-p4.py
index 03829f796d..e8f31339e4 100755
--- a/git-p4.py
+++ b/git-p4.py
@@ -716,7 +716,23 @@ def isModeExecChanged(src_mode, dst_mode):
     return isModeExec(src_mode) != isModeExec(dst_mode)
 
 def p4CmdList(cmd, stdin=None, stdin_mode='w+b', cb=None, skip_info=False,
-        errors_as_exceptions=False):
+        errors_as_exceptions=False, encode_cmd_output=True):
+    """ Executes a P4 command:  'cmd' optionally passing 'stdin' to the command's
+        standard input via a temporary file with 'stdin_mode' mode.
+
+        Output from the command is optionally passed to the callback function 'cb'.
+        If 'cb' is None, the response from the command is parsed into a list
+        of resulting dictionaries. (For each block read from the process pipe.)
+
+        If 'skip_info' is true, information in a block read that has a code type of
+        'info' will be skipped.
+
+        If 'errors_as_exceptions' is set to true (the default is false) the error
+        code returned from the execution will generate an exception.
+
+        If 'encode_cmd_output' is set to true (the default) the data that is returned
+        by this function will be passed through the "as_string" function.
+    """
 
     if not isinstance(cmd, list):
         cmd = "-G " + cmd
@@ -739,7 +755,7 @@ def p4CmdList(cmd, stdin=None, stdin_mode='w+b', cb=None, skip_info=False,
             stdin_file.write(stdin)
         else:
             for i in stdin:
-                stdin_file.write(i + '\n')
+                stdin_file.write(as_bytes(i) + b'\n')
         stdin_file.flush()
         stdin_file.seek(0)
 
@@ -753,12 +769,15 @@ def p4CmdList(cmd, stdin=None, stdin_mode='w+b', cb=None, skip_info=False,
         while True:
             entry = marshal.load(p4.stdout)
             if skip_info:
-                if 'code' in entry and entry['code'] == 'info':
+                if b'code' in entry and entry[b'code'] == b'info':
                     continue
             if cb is not None:
                 cb(entry)
             else:
-                result.append(entry)
+                out = {}
+                for key, value in entry.items():
+                    out[as_string(key)] = (as_string(value) if encode_cmd_output else value)
+                result.append(out)
     except EOFError:
         pass
     exitCode = p4.wait()
@@ -785,8 +804,9 @@ def p4CmdList(cmd, stdin=None, stdin_mode='w+b', cb=None, skip_info=False,
 
     return result
 
-def p4Cmd(cmd):
-    list = p4CmdList(cmd)
+def p4Cmd(cmd, encode_cmd_output=True):
+    """Executes a P4 command and returns the results in a dictionary"""
+    list = p4CmdList(cmd, encode_cmd_output=encode_cmd_output)
     result = {}
     for entry in list:
         result.update(entry)
@@ -1165,7 +1185,7 @@ def getClientSpec():
     """Look at the p4 client spec, create a View() object that contains
        all the mappings, and return it."""
 
-    specList = p4CmdList("client -o")
+    specList = p4CmdList("client -o", encode_cmd_output=False)
     if len(specList) != 1:
         die('Output from "client -o" is %d lines, expecting 1' %
             len(specList))
@@ -2609,7 +2629,7 @@ def update_client_spec_path_cache(self, files):
         if len(fileArgs) == 0:
             return  # All files in cache
 
-        where_result = p4CmdList(["-x", "-", "where"], stdin=fileArgs)
+        where_result = p4CmdList(["-x", "-", "where"], stdin=fileArgs, encode_cmd_output=False)
         for res in where_result:
             if "code" in res and res["code"] == "error":
                 # assume error is "... file(s) not in client view"
-- 
gitgitgadget
Previous: Ben Keene via GitGitGadgetNext: Jeff King
Message 67 of 77 in “git-p4.py: Cast byte strings to unicode strings in python3”
  1. 0/1 git-p4.py: Cast byte strings to unicode strings in python3Ben Keene via GitGitGadget, Nov 13, 2019
  2. 1/1 Cast byte strings to unicode strings in python3Ben Keene via GitGitGadget, Nov 13, 2019
  3. Junio C HamanoNov 14, 2019
  4. Luke DiamandNov 14, 2019
  5. 0/3 git-p4.py: Cast byte strings to unicode strings in python3Ben Keene via GitGitGadget, Nov 15, 2019
  6. 1/3 Cast byte strings to unicode strings in python3Ben Keene via GitGitGadget, Nov 15, 2019
  7. 2/3 FIX: cast as unicode fails when a value is already unicodeBen Keene via GitGitGadget, Nov 15, 2019
  8. 3/3 FIX: wrap return for read_pipe_lines in ustring() and wrap GitLFS read of the pointer file in ustring()Ben Keene via GitGitGadget, Nov 15, 2019
  9. 0/1 git-p4.py: Cast byte strings to unicode strings in python3Ben Keene via GitGitGadget, Dec 2, 2019
  10. 1/1 Python3 support for t9800 tests. Basic P4/Python3 supportBen Keene via GitGitGadget, Dec 2, 2019
  11. Denton LiuDec 3, 2019
  12. Ben KeeneDec 3, 2019
  13. Denton LiuDec 4, 2019
  14. 00/11 git-p4.py: Cast byte strings to unicode strings in python3Ben Keene via GitGitGadget, Dec 4, 2019
  15. 01/11 git-p4: select p4 binary by operating-systemBen Keene via GitGitGadget, Dec 4, 2019
  16. Denton LiuDec 5, 2019
  17. Ben KeeneDec 5, 2019
  18. 02/11 git-p4: change the expansion test from basestring to listBen Keene via GitGitGadget, Dec 4, 2019
  19. Denton LiuDec 5, 2019
  20. Ben KeeneDec 5, 2019
  21. 03/11 git-p4: add new helper functions for python3 conversionBen Keene via GitGitGadget, Dec 4, 2019
  22. Denton LiuDec 5, 2019
  23. Ben KeeneDec 5, 2019
  24. 05/11 git-p4: Add new functions in preparation of usageBen Keene via GitGitGadget, Dec 4, 2019
  25. Denton LiuDec 5, 2019
  26. Ben KeeneDec 5, 2019
  27. 04/11 git-p4: python3 syntax changesBen Keene via GitGitGadget, Dec 4, 2019
  28. Denton LiuDec 5, 2019
  29. 08/11 git-p4: p4CmdList - support Unicode encodingBen Keene via GitGitGadget, Dec 4, 2019
  30. Junio C HamanoDec 5, 2019
  31. Ben KeeneDec 5, 2019
  32. 07/11 git-p4: Add a helper class for stream writingBen Keene via GitGitGadget, Dec 4, 2019
  33. Junio C HamanoDec 5, 2019
  34. Ben KeeneDec 5, 2019
  35. 06/11 git-p4: Fix assumed path separators to be more Windows friendlyBen Keene via GitGitGadget, Dec 4, 2019
  36. Junio C HamanoDec 5, 2019
  37. Ben KeeneDec 5, 2019
  38. 09/11 git-p4: Add usability enhancementsBen Keene via GitGitGadget, Dec 4, 2019
  39. Junio C HamanoDec 5, 2019
  40. Ben KeeneDec 5, 2019
  41. 10/11 git-p4: Support python3 for basic P4 clone, sync, and submitBen Keene via GitGitGadget, Dec 4, 2019
  42. 11/11 git-p4: Added --encoding parameter to p4 cloneBen Keene via GitGitGadget, Dec 4, 2019
  43. Luke DiamandDec 5, 2019
  44. Ben KeeneDec 5, 2019
  45. Denton LiuDec 5, 2019
  46. Ben KeeneDec 5, 2019
  47. 00/15 git-p4.py: Cast byte strings to unicode strings in python3Ben Keene via GitGitGadget, Dec 7, 2019
  48. 01/15 t/gitweb-lib.sh: drop confusing quotesJeff King via GitGitGadget, Dec 7, 2019
  49. 02/15 t/gitweb-lib.sh: set $REQUEST_URIJeff King via GitGitGadget, Dec 7, 2019
  50. 03/15 git-p4: select P4 binary by operating-systemBen Keene via GitGitGadget, Dec 7, 2019
  51. Junio C HamanoDec 9, 2019
  52. 05/15 git-p4: promote encodeWithUTF8() to a global functionBen Keene via GitGitGadget, Dec 7, 2019
  53. Junio C HamanoDec 11, 2019
  54. 04/15 git-p4: change the expansion test from basestring to listBen Keene via GitGitGadget, Dec 7, 2019
  55. Junio C HamanoDec 9, 2019
  56. Ben KeeneDec 13, 2019
  57. 06/15 git-p4: remove p4_write_pipe() and write_pipe() return valuesBen Keene via GitGitGadget, Dec 7, 2019
  58. 11/15 git-p4: add Py23File() - helper class for stream writingBen Keene via GitGitGadget, Dec 7, 2019
  59. 08/15 git-p4: add casting helper functions for python 3 conversionBen Keene via GitGitGadget, Dec 7, 2019
  60. 09/15 git-p4: python 3 syntax changesBen Keene via GitGitGadget, Dec 7, 2019
  61. 10/15 git-p4: fix assumed path separators to be more Windows friendlyBen Keene via GitGitGadget, Dec 7, 2019
  62. 15/15 git-p4: Add depot manipulation functionsBen Keene via GitGitGadget, Dec 7, 2019
  63. 14/15 git-p4: added --encoding parameter to p4 cloneBen Keene via GitGitGadget, Dec 7, 2019
  64. 07/15 git-p4: add new support function gitConfigSet()Ben Keene via GitGitGadget, Dec 7, 2019
  65. Junio C HamanoDec 11, 2019
  66. 13/15 git-p4: support Python 3 for basic P4 clone, sync, and submit (t9800)Ben Keene via GitGitGadget, Dec 7, 2019
  67. 12/15 git-p4: p4CmdList - support Unicode encodingBen Keene via GitGitGadget, Dec 7, 2019
  68. Jeff KingDec 7, 2019
  69. Ben KeeneDec 7, 2019
  70. Junio C HamanoDec 11, 2019
  71. Denton LiuDec 11, 2019
  72. Junio C HamanoDec 11, 2019
  73. Luke DiamandDec 11, 2019
  74. Junio C HamanoDec 11, 2019
  75. Yang ZhaoDec 11, 2019
  76. Ben KeeneDec 12, 2019
  77. Ben KeeneDec 13, 2019

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.