docket.py
75 lines
| 2.4 KiB
| text/x-python
|
PythonLexer
|
r48474 | # 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" | ||||
|
r48482 | # Must match the constant of the same name in | ||
# `rust/hg-core/src/dirstate_tree/on_disk.rs` | ||||
|
r48484 | TREE_METADATA_SIZE = 44 | ||
|
r48482 | |||
|
r48474 | # * 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 | ||||
|
r48977 | # * {TREE_METADATA_SIZE} bytes: tree metadata, parsed separately | ||
|
r48474 | # * 4 bytes: big-endian used size of the data file | ||
# * 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) | ||||
|
r48482 | HEADER = struct.Struct( | ||
|
r48977 | ">{}s32s32s{}sLB".format(len(V2_FORMAT_MARKER), TREE_METADATA_SIZE) | ||
|
r48482 | ) | ||
|
r48474 | |||
class DirstateDocket(object): | ||||
|
r48780 | data_filename_pattern = b'dirstate.%s' | ||
|
r48474 | |||
|
r48482 | def __init__(self, parents, data_size, tree_metadata, uuid): | ||
|
r48474 | self.parents = parents | ||
self.data_size = data_size | ||||
|
r48482 | self.tree_metadata = tree_metadata | ||
|
r48474 | self.uuid = uuid | ||
@classmethod | ||||
|
r48482 | def with_new_uuid(cls, parents, data_size, tree_metadata): | ||
return cls(parents, data_size, tree_metadata, docket_mod.make_uid()) | ||||
|
r48474 | |||
@classmethod | ||||
def parse(cls, data, nodeconstants): | ||||
if not data: | ||||
parents = (nodeconstants.nullid, nodeconstants.nullid) | ||||
|
r48482 | return cls(parents, 0, b'', None) | ||
|
r48977 | marker, p1, p2, meta, data_size, uuid_size = HEADER.unpack_from(data) | ||
|
r48474 | 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] | ||||
|
r48482 | return cls((p1, p2), data_size, meta, uuid) | ||
|
r48474 | |||
def serialize(self): | ||||
p1, p2 = self.parents | ||||
header = HEADER.pack( | ||||
|
r48482 | V2_FORMAT_MARKER, | ||
p1, | ||||
p2, | ||||
|
r48977 | self.tree_metadata, | ||
|
r48482 | self.data_size, | ||
len(self.uuid), | ||||
|
r48474 | ) | ||
return header + self.uuid | ||||
def data_filename(self): | ||||
return self.data_filename_pattern % self.uuid | ||||