<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Sun, Nov 13, 2016 at 2:30 AM, Stanislau Hlebik <span dir="ltr"><<a href="mailto:stash@fb.com" target="_blank">stash@fb.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"># HG changeset patch<br>
# User Stanislau Hlebik <<a href="mailto:stash@fb.com">stash@fb.com</a>><br>
# Date 1479032456 28800<br>
#      Sun Nov 13 02:20:56 2016 -0800<br>
# Branch stable<br>
# Node ID 8b6ab3b8df3aae90ac72d7fa4603e7<wbr>d5b4ab55e9<br>
# Parent  0917ce41b232a5fc2a6e503cbad158<wbr>79e037a2f9<br>
bookmarks: introduce binary encoding<br>
<br>
Bookmarks binary encoding will be used for `bookmarks` bundle2 part.<br>
The format is: <4 bytes - bookmark size, big-endian><bookmark><br>
               <1 byte - 0 if node is empty 1 otherwise><20 bytes node><br>
BookmarksEncodeError and BookmarksDecodeError maybe thrown if input is<br>
incorrect.<br></blockquote><div><br></div><div>I'm pretty happy with this series up until and including this patch.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
diff --git a/mercurial/bookmarks.py b/mercurial/bookmarks.py<br>
--- a/mercurial/bookmarks.py<br>
+++ b/mercurial/bookmarks.py<br>
@@ -8,7 +8,9 @@<br>
 from __future__ import absolute_import<br>
<br>
 import errno<br>
+import io<br>
 import os<br>
+import struct<br>
<br>
 from .i18n import _<br>
 from .node import (<br>
@@ -23,6 +25,71 @@<br>
     util,<br>
 )<br>
<br>
+_NONEMPTYNODE = struct.pack('?', False)<br>
+_EMPTYNODE = struct.pack('?', True)<br>
+<br>
+def _unpackbookmarksize(stream):<br>
+    """Returns 0 if stream is empty.<br>
+    """<br>
+<br>
+    intstruct = struct.Struct('>i')<br>
+    expectedsize = intstruct.size<br>
+    encodedbookmarksize = stream.read(expectedsize)<br>
+    if not encodedbookmarksize:<br>
+        return 0<br>
+    if len(encodedbookmarksize) != expectedsize:<br>
+        raise ValueError(<br>
+            _('cannot decode bookmark size: '<br>
+              'expected size: %d, actual size: %d') %<br>
+            (expectedsize, len(encodedbookmarksize)))<br>
+    return intstruct.unpack(<wbr>encodedbookmarksize)[0]<br>
+<br>
+def encodebookmarks(bookmarks):<br>
+    """Encodes bookmark to node mapping to the byte string.<br>
+<br>
+    Format: <4 bytes - bookmark size><bookmark><br>
+            <1 byte - 0 if node is empty 1 otherwise><20 bytes node><br>
+    Node may be 20 byte binary string or empty<br>
+    """<br>
+<br>
+    intstruct = struct.Struct('>i')<br>
+    for bookmark, node in sorted(bookmarks.iteritems()):<br>
+        yield intstruct.pack(len(bookmark))<br>
+        yield encoding.fromlocal(bookmark)<br>
+        if node:<br>
+            if len(node) != 20:<br>
+                raise ValueError(_('node must be 20 or bytes long'))<br>
+            yield _NONEMPTYNODE<br>
+            yield node<br>
+        else:<br>
+            yield _EMPTYNODE<br>
+<br>
+def decodebookmarks(buf):<br>
+    """Decodes buffer into bookmark to node mapping.<br>
+<br>
+    Node is either 20 bytes or empty.<br>
+    """<br>
+<br>
+    stream = io.BytesIO(buf)<br>
+    bookmarks = {}<br>
+    bookmarksize = _unpackbookmarksize(stream)<br>
+    boolstruct = struct.Struct('?')<br>
+    while bookmarksize:<br>
+        bookmark = stream.read(bookmarksize)<br>
+        if len(bookmark) != bookmarksize:<br>
+            raise ValueError(<br>
+                _('cannot decode bookmark: expected size: %d, '<br>
+                'actual size: %d') % (bookmarksize, len(bookmark)))<br>
+        bookmark = encoding.tolocal(bookmark)<br>
+        packedemptynodeflag = stream.read(boolstruct.size)<br>
+        emptynode = boolstruct.unpack(<wbr>packedemptynodeflag)[0]<br>
+        node = ''<br>
+        if not emptynode:<br>
+            node = stream.read(20)<br>
+        bookmarks[bookmark] = node<br>
+        bookmarksize = _unpackbookmarksize(stream)<br>
+    return bookmarks<br>
+<br>
 def _getbkfile(repo):<br>
     """Hook so that extensions that mess with the store can hook bm storage.<br>
<br>
______________________________<wbr>_________________<br>
Mercurial-devel mailing list<br>
<a href="mailto:Mercurial-devel@mercurial-scm.org">Mercurial-devel@mercurial-scm.<wbr>org</a><br>
<a href="https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel" rel="noreferrer" target="_blank">https://www.mercurial-scm.org/<wbr>mailman/listinfo/mercurial-<wbr>devel</a><br>
</blockquote></div><br></div></div>