[PATCH 7 of 7] client: handle commit messages with \0 characters for all commands

Mathias De Mare mathias.de_mare at nokia.com
Tue Mar 14 08:26:39 UTC 2023


# HG changeset patch
# User Mathias De Mare <mathias.de_mare at nokia.com>
# Date 1678717940 -3600
#      Mon Mar 13 15:32:20 2023 +0100
# Node ID c2482b94ad1f644612d7e063e84d6f56b0d3b773
# Parent  c1d60b0bf6f30b40fac5084132f0c0d266dfae82
client: handle commit messages with \0 characters for all commands

Each of the impacted commands will now use the 'json' template,
which they all support as of Mercurial 3.7.3 (the first version
tested in the regression tests).

Note: I tried to add a test with null bytes,
but both hglib and using hg directly through subprocess
rejected adding a commit message with a null byte.

diff --git a/hglib/client.py b/hglib/client.py
--- a/hglib/client.py
+++ b/hglib/client.py
@@ -159,20 +159,6 @@ class hgclient(object):
             return channel, self.server.stdout.read(length)
 
     @staticmethod
-    def _parserevs(splitted):
-        '''splitted is a list of fields according to our rev.style, where
-        each 6 fields compose one revision.
-        '''
-        revs = []
-        for rev in util.grouper(7, splitted):
-            # truncate the timezone and convert to a local datetime
-            posixtime = float(rev[6].split(b('.'), 1)[0])
-            dt = datetime.datetime.fromtimestamp(posixtime)
-            revs.append(revision(rev[0], rev[1], rev[2], rev[3],
-                                 rev[4], rev[5], dt))
-        return revs
-
-    @staticmethod
     def _parsejsonrevs(jsonrevs):
         revs = []
         for rev in jsonrevs:
@@ -929,7 +915,7 @@ class hgclient(object):
             rev = [rev]
 
         args = cmdbuilder(b('heads'), r=startrev, t=topological, c=closed,
-                          template=templates.changeset, hidden=self.hidden,
+                          template="json", hidden=self.hidden,
                           *rev)
 
         def eh(ret, out, err):
@@ -937,8 +923,12 @@ class hgclient(object):
                 raise error.CommandError(args, ret, out, err)
             return b('')
 
-        out = self.rawcommand(args, eh=eh).split(b('\0'))[:-1]
-        return self._parserevs(out)
+        out = self.rawcommand(args, eh=eh)
+        if not out:
+            return []
+        json_out = json.loads(out)
+
+        return self._parsejsonrevs(json_out)
 
     def identify(self, rev=None, source=None, num=False, id=False, branch=False,
                  tags=False, bookmarks=False):
@@ -1036,7 +1026,7 @@ class hgclient(object):
 
         """
         args = cmdbuilder(b('incoming'), path,
-                          template=templates.changeset, r=revrange,
+                          template="json", r=revrange,
                           f=force, n=newest, bundle=bundle,
                           B=bookmarks, b=branch, l=limit, M=nomerges,
                           S=subrepos)
@@ -1050,14 +1040,15 @@ class hgclient(object):
             return []
 
         out = util.eatlines(out, 2)
+
         if bookmarks:
             bms = []
             for line in out.splitlines():
                 bms.append(tuple(line.split()))
             return bms
         else:
-            out = out.split(b('\0'))[:-1]
-            return self._parserevs(out)
+            json_out = json.loads(out)
+            return self._parsejsonrevs(json_out)
 
     def log(self, revrange=None, files=[], follow=False,
             followfirst=False, date=None, copies=False, keyword=None,
@@ -1235,7 +1226,7 @@ class hgclient(object):
         """
         args = cmdbuilder(b('outgoing'),
                           path,
-                          template=templates.changeset, r=revrange,
+                          template="json", r=revrange,
                           f=force, n=newest, B=bookmarks,
                           b=branch, S=subrepos)
 
@@ -1254,8 +1245,8 @@ class hgclient(object):
                 bms.append(tuple(line.split()))
             return bms
         else:
-            out = out.split(b('\0'))[:-1]
-            return self._parserevs(out)
+            json_out = json.loads(out)
+            return self._parsejsonrevs(json_out)
 
     def parents(self, rev=None, file=None):
         """Return the working directory's parent revisions. If rev is given,
@@ -1265,16 +1256,19 @@ class hgclient(object):
         is returned.
 
         """
-        args = cmdbuilder(b('parents'), file, template=templates.changeset,
+        args = cmdbuilder(b('parents'), file, template="json",
                           r=rev, hidden=self.hidden)
 
         out = self.rawcommand(args)
         if not out:
             return
 
-        out = out.split(b('\0'))[:-1]
+        json_out = json.loads(out)
 
-        return self._parserevs(out)
+        if not json_out:
+            return
+
+        return self._parsejsonrevs(json_out)
 
     def paths(self, name=None):
         """
@@ -1682,12 +1676,12 @@ class hgclient(object):
         changeset most recently added to the repository (and therefore the most
         recently changed head).
         """
-        args = cmdbuilder(b('tip'), template=templates.changeset,
+        args = cmdbuilder(b('tip'), template="json",
                           hidden=self.hidden)
         out = self.rawcommand(args)
-        out = out.split(b('\0'))
+        json_out = json.loads(out)
 
-        return self._parserevs(out)[0]
+        return self._parsejsonrevs(json_out)[0]
 
     def update(self, rev=None, clean=False, check=False, date=None):
         """



More information about the Mercurial-devel mailing list