view mercurial/dirstateutils/docket.py @ 47770:460e479be66e

typing: add several assertions to dirstatemap to appease pytype I think it's been mentioned in IRC that these can't be None in this case. This fixes: File "/mnt/c/Users/Matt/hg/mercurial/dirstatemap.py", line 213, in addfile: unsupported operand type(s) for &: 'None' and 'int' [unsupported-operands] No attribute '__and__' on None or '__rand__' on int Called from (traceback): line 290, in reset_state File "/mnt/c/Users/Matt/hg/mercurial/dirstatemap.py", line 214, in addfile: unsupported operand type(s) for &: 'None' and 'int' [unsupported-operands] No attribute '__and__' on None or '__rand__' on int Called from (traceback): line 290, in reset_state Differential Revision: https://phab.mercurial-scm.org/D11235
author Matt Harbison <matt_harbison@yahoo.com>
date Fri, 30 Jul 2021 00:11:56 -0400
parents 852262e2e7d9
children 681851d6409b
line wrap: on
line source

# dirstatedocket.py - docket file for dirstate-v2
#
# Copyright Mercurial Contributors
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.

from __future__ import absolute_import

import struct

from ..revlogutils import docket as docket_mod


V2_FORMAT_MARKER = b"dirstate-v2\n"

# Must match the constant of the same name in
# `rust/hg-core/src/dirstate_tree/on_disk.rs`
TREE_METADATA_SIZE = 44

# * 12 bytes: format marker
# * 32 bytes: node ID of the working directory's first parent
# * 32 bytes: node ID of the working directory's second parent
# * 4 bytes: big-endian used size of the data file
# * {TREE_METADATA_SIZE} bytes: tree metadata, parsed separately
# * 1 byte: length of the data file's UUID
# * variable: data file's UUID
#
# Node IDs are null-padded if shorter than 32 bytes.
# A data file shorter than the specified used size is corrupted (truncated)
HEADER = struct.Struct(
    ">{}s32s32sL{}sB".format(len(V2_FORMAT_MARKER), TREE_METADATA_SIZE)
)


class DirstateDocket(object):
    data_filename_pattern = b'dirstate.%s.d'

    def __init__(self, parents, data_size, tree_metadata, uuid):
        self.parents = parents
        self.data_size = data_size
        self.tree_metadata = tree_metadata
        self.uuid = uuid

    @classmethod
    def with_new_uuid(cls, parents, data_size, tree_metadata):
        return cls(parents, data_size, tree_metadata, docket_mod.make_uid())

    @classmethod
    def parse(cls, data, nodeconstants):
        if not data:
            parents = (nodeconstants.nullid, nodeconstants.nullid)
            return cls(parents, 0, b'', None)
        marker, p1, p2, data_size, meta, uuid_size = HEADER.unpack_from(data)
        if marker != V2_FORMAT_MARKER:
            raise ValueError("expected dirstate-v2 marker")
        uuid = data[HEADER.size : HEADER.size + uuid_size]
        p1 = p1[: nodeconstants.nodelen]
        p2 = p2[: nodeconstants.nodelen]
        return cls((p1, p2), data_size, meta, uuid)

    def serialize(self):
        p1, p2 = self.parents
        header = HEADER.pack(
            V2_FORMAT_MARKER,
            p1,
            p2,
            self.data_size,
            self.tree_metadata,
            len(self.uuid),
        )
        return header + self.uuid

    def data_filename(self):
        return self.data_filename_pattern % self.uuid