Patchwork [01,of,12,V3] bookmark: add methods to binary encode and decode bookmark values

login
register
mail settings
Submitter Boris Feld
Date Nov. 20, 2017, 4:51 p.m.
Message ID <d3d4513977af55bd80af.1511196712@FB>
Download mbox | patch
Permalink /patch/25656/
State Accepted
Headers show

Comments

Boris Feld - Nov. 20, 2017, 4:51 p.m.
# HG changeset patch
# User Boris Feld <boris.feld@octobus.net>
# Date 1508072395 -7200
#      Sun Oct 15 14:59:55 2017 +0200
# Node ID d3d4513977af55bd80afee86818d7ef4e9c25aca
# Parent  62e10bf001a9014d181966c6bca9958d105ef359
# EXP-Topic b2.bookmarks
# Available At https://bitbucket.org/octobus/mercurial-devel/
#              hg pull https://bitbucket.org/octobus/mercurial-devel/ -r d3d4513977af
bookmark: add methods to binary encode and decode bookmark values

Coming new bundle2 parts related to bookmark will use a binary encoding. It
encodes a series of '(bookmark, node)' pairs. Bookmark name has a high enough
size limit to not be affected by issue5165. (64K length, we are well covered)
Boris Feld - Nov. 27, 2017, 4:27 p.m.
Any update on the review status of this series?

On Mon, 2017-11-20 at 17:51 +0100, Boris Feld wrote:
> # HG changeset patch
> # User Boris Feld <boris.feld@octobus.net>
> # Date 1508072395 -7200
> #      Sun Oct 15 14:59:55 2017 +0200
> # Node ID d3d4513977af55bd80afee86818d7ef4e9c25aca
> # Parent  62e10bf001a9014d181966c6bca9958d105ef359
> # EXP-Topic b2.bookmarks
> # Available At https://bitbucket.org/octobus/mercurial-devel/
> #              hg pull https://bitbucket.org/octobus/mercurial-devel/
>  -r d3d4513977af
> bookmark: add methods to binary encode and decode bookmark values
> 
> Coming new bundle2 parts related to bookmark will use a binary
> encoding. It
> encodes a series of '(bookmark, node)' pairs. Bookmark name has a
> high enough
> size limit to not be affected by issue5165. (64K length, we are well
> covered)
> 
> diff --git a/mercurial/bookmarks.py b/mercurial/bookmarks.py
> --- a/mercurial/bookmarks.py
> +++ b/mercurial/bookmarks.py
> @@ -8,12 +8,14 @@
>  from __future__ import absolute_import
>  
>  import errno
> +import struct
>  
>  from .i18n import _
>  from .node import (
>      bin,
>      hex,
>      short,
> +    wdirid,
>  )
>  from . import (
>      encoding,
> @@ -550,6 +552,60 @@ def unhexlifybookmarks(marks):
>          binremotemarks[name] = bin(node)
>      return binremotemarks
>  
> +_binaryentry = struct.Struct('>20sH')
> +
> +def binaryencode(bookmarks):
> +    """encode a '(bookmark, node)' iterable into a binary stream
> +
> +    the binary format is:
> +
> +        <node><bookmark-length><bookmark-name>
> +
> +    :node: is a 20 bytes binary node,
> +    :bookmark-length: an unsigned short,
> +    :bookmark-name: the name of the bookmark (of length <bookmark-
> length>)
> +
> +    wdirid (all bits set) will be used as a special value for
> "missing"
> +    """
> +    binarydata = []
> +    for book, node in bookmarks:
> +        if not node: # None or ''
> +            node = wdirid
> +        binarydata.append(_binaryentry.pack(node, len(book)))
> +        binarydata.append(book)
> +    return ''.join(binarydata)
> +
> +def binarydecode(stream):
> +    """decode a binary stream into an '(bookmark, node)' iterable
> +
> +    the binary format is:
> +
> +        <node><bookmark-length><bookmark-name>
> +
> +    :node: is a 20 bytes binary node,
> +    :bookmark-length: an unsigned short,
> +    :bookmark-name: the name of the bookmark (of length <bookmark-
> length>))
> +
> +    wdirid (all bits set) will be used as a special value for
> "missing"
> +    """
> +    entrysize = _binaryentry.size
> +    books = []
> +    while True:
> +        entry = stream.read(entrysize)
> +        if len(entry) < entrysize:
> +            if entry:
> +                raise error.Abort(_('bad bookmark stream'))
> +            break
> +        node, length = _binaryentry.unpack(entry)
> +        bookmark = stream.read(length)
> +        if len(bookmark) < length:
> +            if entry:
> +                raise error.Abort(_('bad bookmark stream'))
> +        if node == wdirid:
> +            node = None
> +        books.append((bookmark, node))
> +    return books
> +
>  def updatefromremote(ui, repo, remotemarks, path, trfunc,
> explicit=()):
>      ui.debug("checking for updated bookmarks\n")
>      localmarks = repo._bookmarks

Patch

diff --git a/mercurial/bookmarks.py b/mercurial/bookmarks.py
--- a/mercurial/bookmarks.py
+++ b/mercurial/bookmarks.py
@@ -8,12 +8,14 @@ 
 from __future__ import absolute_import
 
 import errno
+import struct
 
 from .i18n import _
 from .node import (
     bin,
     hex,
     short,
+    wdirid,
 )
 from . import (
     encoding,
@@ -550,6 +552,60 @@  def unhexlifybookmarks(marks):
         binremotemarks[name] = bin(node)
     return binremotemarks
 
+_binaryentry = struct.Struct('>20sH')
+
+def binaryencode(bookmarks):
+    """encode a '(bookmark, node)' iterable into a binary stream
+
+    the binary format is:
+
+        <node><bookmark-length><bookmark-name>
+
+    :node: is a 20 bytes binary node,
+    :bookmark-length: an unsigned short,
+    :bookmark-name: the name of the bookmark (of length <bookmark-length>)
+
+    wdirid (all bits set) will be used as a special value for "missing"
+    """
+    binarydata = []
+    for book, node in bookmarks:
+        if not node: # None or ''
+            node = wdirid
+        binarydata.append(_binaryentry.pack(node, len(book)))
+        binarydata.append(book)
+    return ''.join(binarydata)
+
+def binarydecode(stream):
+    """decode a binary stream into an '(bookmark, node)' iterable
+
+    the binary format is:
+
+        <node><bookmark-length><bookmark-name>
+
+    :node: is a 20 bytes binary node,
+    :bookmark-length: an unsigned short,
+    :bookmark-name: the name of the bookmark (of length <bookmark-length>))
+
+    wdirid (all bits set) will be used as a special value for "missing"
+    """
+    entrysize = _binaryentry.size
+    books = []
+    while True:
+        entry = stream.read(entrysize)
+        if len(entry) < entrysize:
+            if entry:
+                raise error.Abort(_('bad bookmark stream'))
+            break
+        node, length = _binaryentry.unpack(entry)
+        bookmark = stream.read(length)
+        if len(bookmark) < length:
+            if entry:
+                raise error.Abort(_('bad bookmark stream'))
+        if node == wdirid:
+            node = None
+        books.append((bookmark, node))
+    return books
+
 def updatefromremote(ui, repo, remotemarks, path, trfunc, explicit=()):
     ui.debug("checking for updated bookmarks\n")
     localmarks = repo._bookmarks