mercurial/dirstateutils/v2.py
author Matt Harbison <matt_harbison@yahoo.com>
Wed, 14 Aug 2024 03:25:16 -0400
changeset 51801 62b25293b620
parent 51729 278af66e6595
child 51863 f4733654f144
permissions -rw-r--r--
typing: correct a type hint in `mercurial.manifest` Obvious typo that was flagged by PyCharm.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
48221
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
     1
# v2.py - Pure-Python implementation of the dirstate-v2 file format
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
     2
#
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
     3
# Copyright Mercurial Contributors
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
     4
#
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
     5
# This software may be used and distributed according to the terms of the
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
     6
# GNU General Public License version 2 or any later version.
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
     7
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
     8
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
     9
import struct
51729
278af66e6595 typing: induce pytype to use the standard `attr` instead of the vendored copy
Matt Harbison <matt_harbison@yahoo.com>
parents: 49550
diff changeset
    10
import typing
48221
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    11
48222
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
    12
from ..thirdparty import attr
51729
278af66e6595 typing: induce pytype to use the standard `attr` instead of the vendored copy
Matt Harbison <matt_harbison@yahoo.com>
parents: 49550
diff changeset
    13
278af66e6595 typing: induce pytype to use the standard `attr` instead of the vendored copy
Matt Harbison <matt_harbison@yahoo.com>
parents: 49550
diff changeset
    14
# Force pytype to use the non-vendored package
278af66e6595 typing: induce pytype to use the standard `attr` instead of the vendored copy
Matt Harbison <matt_harbison@yahoo.com>
parents: 49550
diff changeset
    15
if typing.TYPE_CHECKING:
278af66e6595 typing: induce pytype to use the standard `attr` instead of the vendored copy
Matt Harbison <matt_harbison@yahoo.com>
parents: 49550
diff changeset
    16
    # noinspection PyPackageRequirements
278af66e6595 typing: induce pytype to use the standard `attr` instead of the vendored copy
Matt Harbison <matt_harbison@yahoo.com>
parents: 49550
diff changeset
    17
    import attr
278af66e6595 typing: induce pytype to use the standard `attr` instead of the vendored copy
Matt Harbison <matt_harbison@yahoo.com>
parents: 49550
diff changeset
    18
48222
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
    19
from .. import error, policy
48221
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    20
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    21
parsers = policy.importmod('parsers')
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    22
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    23
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    24
# Must match the constant of the same name in
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    25
# `rust/hg-core/src/dirstate_tree/on_disk.rs`
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    26
TREE_METADATA_SIZE = 44
48231
0524c1359bfc dirstate-v2: Extend node flags to 16 bits
Simon Sapin <simon.sapin@octobus.net>
parents: 48228
diff changeset
    27
NODE_SIZE = 44
48221
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    28
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    29
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    30
# Must match the `TreeMetadata` Rust struct in
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    31
# `rust/hg-core/src/dirstate_tree/on_disk.rs`. See doc-comments there.
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    32
#
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    33
# * 4 bytes: start offset of root nodes
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    34
# * 4 bytes: number of root nodes
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    35
# * 4 bytes: total number of nodes in the tree that have an entry
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    36
# * 4 bytes: total number of nodes in the tree that have a copy source
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    37
# * 4 bytes: number of bytes in the data file that are not used anymore
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    38
# * 4 bytes: unused
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    39
# * 20 bytes: SHA-1 hash of ignore patterns
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    40
TREE_METADATA = struct.Struct('>LLLLL4s20s')
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    41
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    42
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    43
# Must match the `Node` Rust struct in
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    44
# `rust/hg-core/src/dirstate_tree/on_disk.rs`. See doc-comments there.
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    45
#
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    46
# * 4 bytes: start offset of full path
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    47
# * 2 bytes: length of the full path
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    48
# * 2 bytes: length within the full path before its "base name"
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    49
# * 4 bytes: start offset of the copy source if any, or zero for no copy source
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    50
# * 2 bytes: length of the copy source if any, or unused
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    51
# * 4 bytes: start offset of child nodes
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    52
# * 4 bytes: number of child nodes
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    53
# * 4 bytes: number of descendant nodes that have an entry
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    54
# * 4 bytes: number of descendant nodes that have a "tracked" state
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    55
# * 1 byte: flags
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    56
# * 4 bytes: expected size
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    57
# * 4 bytes: mtime seconds
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    58
# * 4 bytes: mtime nanoseconds
48231
0524c1359bfc dirstate-v2: Extend node flags to 16 bits
Simon Sapin <simon.sapin@octobus.net>
parents: 48228
diff changeset
    59
NODE = struct.Struct('>LHHLHLLLLHlll')
48221
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    60
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    61
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    62
assert TREE_METADATA_SIZE == TREE_METADATA.size
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    63
assert NODE_SIZE == NODE.size
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    64
48264
bb240915f69f dirstate-v2: adjust the meaning of directory flags
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48263
diff changeset
    65
# match constant in mercurial/pure/parsers.py
49546
5743e19bb8b0 dirstate-v2: update constant that wasn't kept in sync
Raphaël Gomès <rgomes@octobus.net>
parents: 48946
diff changeset
    66
DIRSTATE_V2_DIRECTORY = 1 << 13
48264
bb240915f69f dirstate-v2: adjust the meaning of directory flags
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48263
diff changeset
    67
48221
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    68
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    69
def parse_dirstate(map, copy_map, data, tree_metadata):
49547
07b9ca52a378 dirstate-v2: fix typos in docstrings
Raphaël Gomès <rgomes@octobus.net>
parents: 49546
diff changeset
    70
    """parse a full v2-dirstate from a binary data into dictionaries:
48221
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    71
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    72
    - map: a {path: entry} mapping that will be filled
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    73
    - copy_map: a {path: copy-source} mapping that will be filled
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    74
    - data: a binary blob contains v2 nodes data
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    75
    - tree_metadata:: a binary blob of the top level node (from the docket)
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    76
    """
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    77
    (
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    78
        root_nodes_start,
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    79
        root_nodes_len,
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    80
        _nodes_with_entry_count,
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    81
        _nodes_with_copy_source_count,
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    82
        _unreachable_bytes,
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    83
        _unused,
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    84
        _ignore_patterns_hash,
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    85
    ) = TREE_METADATA.unpack(tree_metadata)
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    86
    parse_nodes(map, copy_map, data, root_nodes_start, root_nodes_len)
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    87
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    88
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    89
def parse_nodes(map, copy_map, data, start, len):
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    90
    """parse <len> nodes from <data> starting at offset <start>
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    91
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    92
    This is used by parse_dirstate to recursively fill `map` and `copy_map`.
48251
dfc5a505ddc5 dirstate-v2: adds two flag to track the presence of some unrecorded files
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48231
diff changeset
    93
dfc5a505ddc5 dirstate-v2: adds two flag to track the presence of some unrecorded files
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48231
diff changeset
    94
    All directory specific information is ignored and do not need any
48264
bb240915f69f dirstate-v2: adjust the meaning of directory flags
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48263
diff changeset
    95
    processing (DIRECTORY, ALL_UNKNOWN_RECORDED, ALL_IGNORED_RECORDED)
48221
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    96
    """
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    97
    for i in range(len):
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    98
        node_start = start + NODE_SIZE * i
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    99
        node_bytes = slice_with_len(data, node_start, NODE_SIZE)
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   100
        (
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   101
            path_start,
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   102
            path_len,
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   103
            _basename_start,
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   104
            copy_source_start,
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   105
            copy_source_len,
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   106
            children_start,
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   107
            children_count,
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   108
            _descendants_with_entry_count,
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   109
            _tracked_descendants_count,
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   110
            flags,
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   111
            size,
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   112
            mtime_s,
48263
83d0bd45b662 dirstate-v2: actually use sub-second mtime precision
Simon Sapin <simon.sapin@octobus.net>
parents: 48260
diff changeset
   113
            mtime_ns,
48221
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   114
        ) = NODE.unpack(node_bytes)
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   115
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   116
        # Parse child nodes of this node recursively
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   117
        parse_nodes(map, copy_map, data, children_start, children_count)
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   118
48260
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents: 48251
diff changeset
   119
        item = parsers.DirstateItem.from_v2_data(flags, size, mtime_s, mtime_ns)
48221
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   120
        if not item.any_tracked:
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   121
            continue
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   122
        path = slice_with_len(data, path_start, path_len)
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   123
        map[path] = item
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   124
        if copy_source_start:
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   125
            copy_map[path] = slice_with_len(
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   126
                data, copy_source_start, copy_source_len
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   127
            )
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   128
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   129
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   130
def slice_with_len(data, start, len):
a32a96079e2d dirstate-v2: initial Python parser
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   131
    return data[start : start + len]
48222
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   132
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   133
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   134
@attr.s
48946
642e31cb55f0 py3: use class X: instead of class X(object):
Gregory Szorc <gregory.szorc@gmail.com>
parents: 48875
diff changeset
   135
class Node:
48222
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   136
    path = attr.ib()
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   137
    entry = attr.ib()
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   138
    parent = attr.ib(default=None)
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   139
    children_count = attr.ib(default=0)
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   140
    children_offset = attr.ib(default=0)
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   141
    descendants_with_entry = attr.ib(default=0)
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   142
    tracked_descendants = attr.ib(default=0)
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   143
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   144
    def pack(self, copy_map, paths_offset):
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   145
        path = self.path
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   146
        copy = copy_map.get(path)
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   147
        entry = self.entry
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   148
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   149
        path_start = paths_offset
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   150
        path_len = len(path)
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   151
        basename_start = path.rfind(b'/') + 1  # 0 if rfind returns -1
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   152
        if copy is not None:
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   153
            copy_source_start = paths_offset + len(path)
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   154
            copy_source_len = len(copy)
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   155
        else:
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   156
            copy_source_start = 0
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   157
            copy_source_len = 0
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   158
        if entry is not None:
48260
269ff8978086 dirstate: store mtimes with nanosecond precision in memory
Simon Sapin <simon.sapin@octobus.net>
parents: 48251
diff changeset
   159
            flags, size, mtime_s, mtime_ns = entry.v2_data()
48222
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   160
        else:
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   161
            # There are no mtime-cached directories in the Python implementation
48264
bb240915f69f dirstate-v2: adjust the meaning of directory flags
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48263
diff changeset
   162
            flags = DIRSTATE_V2_DIRECTORY
48222
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   163
            size = 0
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   164
            mtime_s = 0
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   165
            mtime_ns = 0
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   166
        return NODE.pack(
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   167
            path_start,
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   168
            path_len,
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   169
            basename_start,
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   170
            copy_source_start,
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   171
            copy_source_len,
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   172
            self.children_offset,
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   173
            self.children_count,
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   174
            self.descendants_with_entry,
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   175
            self.tracked_descendants,
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   176
            flags,
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   177
            size,
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   178
            mtime_s,
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   179
            mtime_ns,
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   180
        )
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   181
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   182
48392
434de12918fd dirstate: remove need_delay logic
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 48264
diff changeset
   183
def pack_dirstate(map, copy_map):
48222
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   184
    """
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   185
    Pack `map` and `copy_map` into the dirstate v2 binary format and return
49548
318bdd289cf2 dirstate-v2: correct documented return values of `pack_dirstate`
Raphaël Gomès <rgomes@octobus.net>
parents: 49547
diff changeset
   186
    the tuple of (data, metadata) bytearrays.
48222
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   187
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   188
    The on-disk format expects a tree-like structure where the leaves are
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   189
    written first (and sorted per-directory), going up levels until the root
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   190
    node and writing that one to the docket. See more details on the on-disk
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   191
    format in `mercurial/helptext/internals/dirstate-v2`.
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   192
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   193
    Since both `map` and `copy_map` are flat dicts we need to figure out the
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   194
    hierarchy. This algorithm does so without having to build the entire tree
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   195
    in-memory: it only keeps the minimum number of nodes around to satisfy the
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   196
    format.
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   197
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   198
    # Algorithm explanation
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   199
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   200
    This explanation does not talk about the different counters for tracked
49547
07b9ca52a378 dirstate-v2: fix typos in docstrings
Raphaël Gomès <rgomes@octobus.net>
parents: 49546
diff changeset
   201
    descendants and storing the copies, but that work is pretty simple once this
48222
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   202
    algorithm is in place.
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   203
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   204
    ## Building a subtree
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   205
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   206
    First, sort `map`: this makes it so the leaves of the tree are contiguous
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   207
    per directory (i.e. a/b/c and a/b/d will be next to each other in the list),
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   208
    and enables us to use the ordering of folders to have a "cursor" of the
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   209
    current folder we're in without ever going twice in the same branch of the
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   210
    tree. The cursor is a node that remembers its parent and any information
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   211
    relevant to the format (see the `Node` class), building the relevant part
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   212
    of the tree lazily.
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   213
    Then, for each file in `map`, move the cursor into the tree to the
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   214
    corresponding folder of the file: for example, if the very first file
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   215
    is "a/b/c", we start from `Node[""]`, create `Node["a"]` which points to
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   216
    its parent `Node[""]`, then create `Node["a/b"]`, which points to its parent
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   217
    `Node["a"]`. These nodes are kept around in a stack.
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   218
    If the next file in `map` is in the same subtree ("a/b/d" or "a/b/e/f"), we
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   219
    add it to the stack and keep looping with the same logic of creating the
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   220
    tree nodes as needed. If however the next file in `map` is *not* in the same
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   221
    subtree ("a/other", if we're still in the "a/b" folder), then we know that
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   222
    the subtree we're in is complete.
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   223
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   224
    ## Writing the subtree
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   225
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   226
    We have the entire subtree in the stack, so we start writing it to disk
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   227
    folder by folder. The way we write a folder is to pop the stack into a list
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   228
    until the folder changes, revert this list of direct children (to satisfy
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   229
    the format requirement that children be sorted). This process repeats until
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   230
    we hit the "other" subtree.
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   231
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   232
    An example:
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   233
        a
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   234
        dir1/b
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   235
        dir1/c
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   236
        dir2/dir3/d
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   237
        dir2/dir3/e
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   238
        dir2/f
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   239
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   240
    Would have us:
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   241
        - add to the stack until "dir2/dir3/e"
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   242
        - realize that "dir2/f" is in a different subtree
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   243
        - pop "dir2/dir3/e", "dir2/dir3/d", reverse them so they're sorted and
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   244
          pack them since the next entry is "dir2/dir3"
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   245
        - go back up to "dir2"
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   246
        - add "dir2/f" to the stack
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   247
        - realize we're done with the map
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   248
        - pop "dir2/f", "dir2/dir3" from the stack, reverse and pack them
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   249
        - go up to the root node, do the same to write "a", "dir1" and "dir2" in
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   250
          that order
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   251
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   252
    ## Special case for the root node
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   253
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   254
    The root node is not serialized in the format, but its information is
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   255
    written to the docket. Again, see more details on the on-disk format in
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   256
    `mercurial/helptext/internals/dirstate-v2`.
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   257
    """
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   258
    data = bytearray()
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   259
    root_nodes_start = 0
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   260
    root_nodes_len = 0
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   261
    nodes_with_entry_count = 0
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   262
    nodes_with_copy_source_count = 0
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   263
    # Will always be 0 since this implementation always re-writes everything
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   264
    # to disk
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   265
    unreachable_bytes = 0
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   266
    unused = b'\x00' * 4
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   267
    # This is an optimization that's only useful for the Rust implementation
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   268
    ignore_patterns_hash = b'\x00' * 20
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   269
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   270
    if len(map) == 0:
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   271
        tree_metadata = TREE_METADATA.pack(
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   272
            root_nodes_start,
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   273
            root_nodes_len,
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   274
            nodes_with_entry_count,
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   275
            nodes_with_copy_source_count,
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   276
            unreachable_bytes,
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   277
            unused,
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   278
            ignore_patterns_hash,
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   279
        )
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   280
        return data, tree_metadata
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   281
49550
fc719967efd0 dirstate-v2: fix edge case where entries aren't sorted
Raphaël Gomès <rgomes@octobus.net>
parents: 49548
diff changeset
   282
    sorted_map = sorted(map.items(), key=lambda x: x[0].split(b"/"))
48222
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   283
49547
07b9ca52a378 dirstate-v2: fix typos in docstrings
Raphaël Gomès <rgomes@octobus.net>
parents: 49546
diff changeset
   284
    # Use a stack to have to only remember the nodes we currently need
48222
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   285
    # instead of building the entire tree in memory
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   286
    stack = []
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   287
    current_node = Node(b"", None)
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   288
    stack.append(current_node)
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   289
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   290
    for index, (path, entry) in enumerate(sorted_map, 1):
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   291
        nodes_with_entry_count += 1
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   292
        if path in copy_map:
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   293
            nodes_with_copy_source_count += 1
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   294
        current_folder = get_folder(path)
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   295
        current_node = move_to_correct_node_in_tree(
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   296
            current_folder, current_node, stack
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   297
        )
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   298
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   299
        current_node.children_count += 1
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   300
        # Entries from `map` are never `None`
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   301
        if entry.tracked:
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   302
            current_node.tracked_descendants += 1
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   303
        current_node.descendants_with_entry += 1
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   304
        stack.append(Node(path, entry, current_node))
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   305
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   306
        should_pack = True
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   307
        next_path = None
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   308
        if index < len(sorted_map):
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   309
            # Determine if the next entry is in the same sub-tree, if so don't
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   310
            # pack yet
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   311
            next_path = sorted_map[index][0]
48741
46d12f7762e4 dirstate-v2: fix infinite loop in pure packer
Raphaël Gomès <rgomes@octobus.net>
parents: 48264
diff changeset
   312
            should_pack = not is_ancestor(next_path, current_folder)
48222
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   313
        if should_pack:
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   314
            pack_directory_children(current_node, copy_map, data, stack)
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   315
            while stack and current_node.path != b"":
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   316
                # Go up the tree and write until we reach the folder of the next
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   317
                # entry (if any, otherwise the root)
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   318
                parent = current_node.parent
48741
46d12f7762e4 dirstate-v2: fix infinite loop in pure packer
Raphaël Gomès <rgomes@octobus.net>
parents: 48264
diff changeset
   319
                in_ancestor_of_next_path = next_path is not None and (
46d12f7762e4 dirstate-v2: fix infinite loop in pure packer
Raphaël Gomès <rgomes@octobus.net>
parents: 48264
diff changeset
   320
                    is_ancestor(next_path, get_folder(stack[-1].path))
48222
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   321
                )
48741
46d12f7762e4 dirstate-v2: fix infinite loop in pure packer
Raphaël Gomès <rgomes@octobus.net>
parents: 48264
diff changeset
   322
                if parent is None or in_ancestor_of_next_path:
48222
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   323
                    break
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   324
                pack_directory_children(parent, copy_map, data, stack)
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   325
                current_node = parent
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   326
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   327
    # Special case for the root node since we don't write it to disk, only its
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   328
    # children to the docket
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   329
    current_node = stack.pop()
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   330
    assert current_node.path == b"", current_node.path
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   331
    assert len(stack) == 0, len(stack)
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   332
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   333
    tree_metadata = TREE_METADATA.pack(
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   334
        current_node.children_offset,
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   335
        current_node.children_count,
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   336
        nodes_with_entry_count,
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   337
        nodes_with_copy_source_count,
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   338
        unreachable_bytes,
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   339
        unused,
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   340
        ignore_patterns_hash,
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   341
    )
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   342
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   343
    return data, tree_metadata
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   344
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   345
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   346
def get_folder(path):
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   347
    """
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   348
    Return the folder of the path that's given, an empty string for root paths.
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   349
    """
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   350
    return path.rsplit(b'/', 1)[0] if b'/' in path else b''
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   351
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   352
48741
46d12f7762e4 dirstate-v2: fix infinite loop in pure packer
Raphaël Gomès <rgomes@octobus.net>
parents: 48264
diff changeset
   353
def is_ancestor(path, maybe_ancestor):
46d12f7762e4 dirstate-v2: fix infinite loop in pure packer
Raphaël Gomès <rgomes@octobus.net>
parents: 48264
diff changeset
   354
    """Returns whether `maybe_ancestor` is an ancestor of `path`.
46d12f7762e4 dirstate-v2: fix infinite loop in pure packer
Raphaël Gomès <rgomes@octobus.net>
parents: 48264
diff changeset
   355
46d12f7762e4 dirstate-v2: fix infinite loop in pure packer
Raphaël Gomès <rgomes@octobus.net>
parents: 48264
diff changeset
   356
    >>> is_ancestor(b"a", b"")
46d12f7762e4 dirstate-v2: fix infinite loop in pure packer
Raphaël Gomès <rgomes@octobus.net>
parents: 48264
diff changeset
   357
    True
46d12f7762e4 dirstate-v2: fix infinite loop in pure packer
Raphaël Gomès <rgomes@octobus.net>
parents: 48264
diff changeset
   358
    >>> is_ancestor(b"a/b/c", b"a/b/c")
46d12f7762e4 dirstate-v2: fix infinite loop in pure packer
Raphaël Gomès <rgomes@octobus.net>
parents: 48264
diff changeset
   359
    False
46d12f7762e4 dirstate-v2: fix infinite loop in pure packer
Raphaël Gomès <rgomes@octobus.net>
parents: 48264
diff changeset
   360
    >>> is_ancestor(b"hgext3rd/__init__.py", b"hgext")
46d12f7762e4 dirstate-v2: fix infinite loop in pure packer
Raphaël Gomès <rgomes@octobus.net>
parents: 48264
diff changeset
   361
    False
46d12f7762e4 dirstate-v2: fix infinite loop in pure packer
Raphaël Gomès <rgomes@octobus.net>
parents: 48264
diff changeset
   362
    >>> is_ancestor(b"hgext3rd/__init__.py", b"hgext3rd")
46d12f7762e4 dirstate-v2: fix infinite loop in pure packer
Raphaël Gomès <rgomes@octobus.net>
parents: 48264
diff changeset
   363
    True
46d12f7762e4 dirstate-v2: fix infinite loop in pure packer
Raphaël Gomès <rgomes@octobus.net>
parents: 48264
diff changeset
   364
    """
46d12f7762e4 dirstate-v2: fix infinite loop in pure packer
Raphaël Gomès <rgomes@octobus.net>
parents: 48264
diff changeset
   365
    if maybe_ancestor == b"":
46d12f7762e4 dirstate-v2: fix infinite loop in pure packer
Raphaël Gomès <rgomes@octobus.net>
parents: 48264
diff changeset
   366
        return True
46d12f7762e4 dirstate-v2: fix infinite loop in pure packer
Raphaël Gomès <rgomes@octobus.net>
parents: 48264
diff changeset
   367
    if path <= maybe_ancestor:
46d12f7762e4 dirstate-v2: fix infinite loop in pure packer
Raphaël Gomès <rgomes@octobus.net>
parents: 48264
diff changeset
   368
        return False
46d12f7762e4 dirstate-v2: fix infinite loop in pure packer
Raphaël Gomès <rgomes@octobus.net>
parents: 48264
diff changeset
   369
    path_components = path.split(b"/")
46d12f7762e4 dirstate-v2: fix infinite loop in pure packer
Raphaël Gomès <rgomes@octobus.net>
parents: 48264
diff changeset
   370
    ancestor_components = maybe_ancestor.split(b"/")
46d12f7762e4 dirstate-v2: fix infinite loop in pure packer
Raphaël Gomès <rgomes@octobus.net>
parents: 48264
diff changeset
   371
    return all(c == o for c, o in zip(path_components, ancestor_components))
46d12f7762e4 dirstate-v2: fix infinite loop in pure packer
Raphaël Gomès <rgomes@octobus.net>
parents: 48264
diff changeset
   372
46d12f7762e4 dirstate-v2: fix infinite loop in pure packer
Raphaël Gomès <rgomes@octobus.net>
parents: 48264
diff changeset
   373
48222
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   374
def move_to_correct_node_in_tree(target_folder, current_node, stack):
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   375
    """
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   376
    Move inside the dirstate node tree to the node corresponding to
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   377
    `target_folder`, creating the missing nodes along the way if needed.
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   378
    """
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   379
    while target_folder != current_node.path:
48741
46d12f7762e4 dirstate-v2: fix infinite loop in pure packer
Raphaël Gomès <rgomes@octobus.net>
parents: 48264
diff changeset
   380
        if is_ancestor(target_folder, current_node.path):
48222
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   381
            # We need to go down a folder
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   382
            prefix = target_folder[len(current_node.path) :].lstrip(b'/')
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   383
            subfolder_name = prefix.split(b'/', 1)[0]
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   384
            if current_node.path:
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   385
                subfolder_path = current_node.path + b'/' + subfolder_name
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   386
            else:
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   387
                subfolder_path = subfolder_name
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   388
            next_node = stack[-1]
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   389
            if next_node.path == target_folder:
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   390
                # This folder is now a file and only contains removed entries
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   391
                # merge with the last node
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   392
                current_node = next_node
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   393
            else:
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   394
                current_node.children_count += 1
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   395
                current_node = Node(subfolder_path, None, current_node)
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   396
                stack.append(current_node)
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   397
        else:
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   398
            # We need to go up a folder
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   399
            current_node = current_node.parent
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   400
    return current_node
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   401
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   402
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   403
def pack_directory_children(node, copy_map, data, stack):
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   404
    """
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   405
    Write the binary representation of the direct sorted children of `node` to
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   406
    `data`
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   407
    """
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   408
    direct_children = []
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   409
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   410
    while stack[-1].path != b"" and get_folder(stack[-1].path) == node.path:
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   411
        direct_children.append(stack.pop())
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   412
    if not direct_children:
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   413
        raise error.ProgrammingError(b"no direct children for %r" % node.path)
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   414
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   415
    # Reverse the stack to get the correct sorted order
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   416
    direct_children.reverse()
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   417
    packed_children = bytearray()
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   418
    # Write the paths to `data`. Pack child nodes but don't write them yet
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   419
    for child in direct_children:
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   420
        packed = child.pack(copy_map=copy_map, paths_offset=len(data))
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   421
        packed_children.extend(packed)
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   422
        data.extend(child.path)
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   423
        data.extend(copy_map.get(child.path, b""))
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   424
        node.tracked_descendants += child.tracked_descendants
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   425
        node.descendants_with_entry += child.descendants_with_entry
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   426
    # Write the fixed-size child nodes all together
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   427
    node.children_offset = len(data)
7e78c72ee3ea dirstate-v2: Initial Python serializer
Raphaël Gomès <rgomes@octobus.net>
parents: 48221
diff changeset
   428
    data.extend(packed_children)