changeset 216:68588c652ac6

client: handle commit messages with \0 characters Mercurial allows commit messages containing \0 characters, but hglib does not properly handle them. By using the json template, these characters are correctly escaped. Note: initial change only modifies this for the 'log' command, I'll follow-up for other commands if this is ok.
author Mathias De Mare <mathias.de_mare@nokia.com>
date Wed, 08 Mar 2023 16:22:21 +0100
parents 1e7a64588ab0
children e86a925ba6a0
files hglib/client.py
diffstat 1 files changed, 17 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/hglib/client.py	Tue Nov 17 13:35:20 2020 -0500
+++ b/hglib/client.py	Wed Mar 08 16:22:21 2023 +0100
@@ -1,4 +1,4 @@
-import struct, re, datetime
+import struct, re, datetime, json
 import hglib
 from hglib import error, util, templates, merge, context
 
@@ -172,6 +172,19 @@
                                  rev[4], rev[5], dt))
         return revs
 
+    @staticmethod
+    def _parsejsonrevs(jsonrevs):
+        revs = []
+        for rev in jsonrevs:
+            # truncate the timezone and convert to a local datetime
+            posixtime = float(rev["date"][0])
+            dt = datetime.datetime.fromtimestamp(posixtime)
+            revs.append(revision(str(rev["rev"]).encode(), rev["node"].encode(),
+                                 ' '.join(rev["tags"]).encode(),
+                                 rev["branch"].encode(), rev["user"].encode(),
+                                 rev["desc"].encode(), dt))
+        return revs
+
     def runcommand(self, args, inchannels, outchannels):
         def writeblock(data):
             if self._protocoltracefn is not None:
@@ -1094,7 +1107,7 @@
         """
         if hidden is None:
             hidden = self.hidden
-        args = cmdbuilder(b('log'), template=templates.changeset,
+        args = cmdbuilder(b('log'), template="json",
                           r=revrange, f=follow, follow_first=followfirst,
                           d=date, C=copies, k=keyword, removed=removed,
                           m=onlymerges, u=user, b=branch, P=prune,
@@ -1102,9 +1115,9 @@
                           hidden=hidden, *files)
 
         out = self.rawcommand(args)
-        out = out.split(b('\0'))[:-1]
+        json_out = json.loads(out)
 
-        return self._parserevs(out)
+        return self._parsejsonrevs(json_out)
 
     def manifest(self, rev=None, all=False):
         """Yields (nodeid, permission, executable, symlink, file path) tuples