##// END OF EJS Templates
tests: skip test-git-interop.t on Windows...
tests: skip test-git-interop.t on Windows Casefolding isn't handled in dirstate yet, triggering a bunch of assertions. But while this is more correctly `no-icasefs`, it's more likely to get attention if someone sees it. I'd just rather not have it adding to the noise on Windows for now. Differential Revision: https://phab.mercurial-scm.org/D10312

File last commit:

r47619:1dc86c2a default
r47656:fe34c75f default
Show More
parsers.py
352 lines | 11.2 KiB | text/x-python | PythonLexer
Martin Geisler
pure Python implementation of parsers.c
r7700 # parsers.py - Python implementation of parsers.c
#
Raphaël Gomès
contributor: change mentions of mpm to olivia...
r47575 # Copyright 2009 Olivia Mackall <olivia@selenic.com> and others
Martin Geisler
pure Python implementation of parsers.c
r7700 #
Martin Geisler
updated license to be explicit about GPL version 2
r8225 # This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
Martin Geisler
pure Python implementation of parsers.c
r7700
Gregory Szorc
parsers: use absolute_import
r27339 from __future__ import absolute_import
import struct
import zlib
revlog: move the nodemap into the index object (for pure)...
r43925 from ..node import nullid, nullrev
from .. import (
pycompat,
util,
)
Augie Fackler
formatting: blacken the codebase...
r43346
revlogutils: move the NodeMap class in a dedicated nodemap module...
r44486 from ..revlogutils import nodemap as nodemaputil
revlog: move the details of revlog "v1" index inside revlog.utils.constants...
r47616 from ..revlogutils import constants as revlog_constants
revlogutils: move the NodeMap class in a dedicated nodemap module...
r44486
Gregory Szorc
util: prefer "bytesio" to "stringio"...
r36976 stringio = pycompat.bytesio
Martin Geisler
pure Python implementation of parsers.c
r7700
Pulkit Goyal
parsers: alias long to int on Python 3
r31220
Martin Geisler
pure Python implementation of parsers.c
r7700 _pack = struct.pack
_unpack = struct.unpack
_compress = zlib.compress
_decompress = zlib.decompress
Siddharth Agarwal
parsers: inline fields of dirstate values in C version...
r21809 # Some code below makes tuples directly because it's more convenient. However,
# code outside this module should always use dirstatetuple.
def dirstatetuple(*x):
# x is a tuple
return x
Augie Fackler
formatting: blacken the codebase...
r43346
Maciej Fijalkowski
pure: write a really lazy version of pure indexObject...
r29133 def gettype(q):
return int(q & 0xFFFF)
Matt Mackall
pure/parsers: fix circular imports, import mercurial modules properly
r7945
Augie Fackler
formatting: blacken the codebase...
r43346
Maciej Fijalkowski
pure: write a really lazy version of pure indexObject...
r29133 def offset_type(offset, type):
Martin von Zweigbergk
pure: use int instead of long...
r31529 return int(int(offset) << 16 | type)
Maciej Fijalkowski
pure: write a really lazy version of pure indexObject...
r29133
Augie Fackler
formatting: blacken the codebase...
r43346
Maciej Fijalkowski
pure: write a really lazy version of pure indexObject...
r29133 class BaseIndexObject(object):
Raphaël Gomès
pure-parsers: document index class constants...
r47380 # Format of an index entry according to Python's `struct` language
revlog: directly use the Struct object for related operation...
r47619 index_format = revlog_constants.INDEX_ENTRY_V1
Raphaël Gomès
pure-parsers: document index class constants...
r47380 # Size of a C unsigned long long int, platform independent
big_int_size = struct.calcsize(b'>Q')
# Size of a C long int, platform independent
int_size = struct.calcsize(b'>i')
# Size of the entire index format
revlog: move the details of revlog "v1" index inside revlog.utils.constants...
r47616 index_size = revlog_constants.INDEX_ENTRY_V1.size
Raphaël Gomès
pure-parsers: document index class constants...
r47380 # An empty index entry, used as a default value to be overridden, or nullrev
Raphaël Gomès
revlog: prepare pure parser for being overloaded...
r47136 null_item = (0, 0, 0, -1, -1, -1, -1, nullid)
revlog: deprecate direct `nodemap` access...
r43974 @property
def nodemap(self):
Denis Laxalde
py3: pass a bytes value for "msg" to nouideprecwarn()...
r44018 msg = b"index.nodemap is deprecated, use index.[has_node|rev|get_rev]"
revlog: deprecate direct `nodemap` access...
r43974 util.nouideprecwarn(msg, b'5.3', stacklevel=2)
return self._nodemap
revlog: move the nodemap into the index object (for pure)...
r43925 @util.propertycache
revlog: deprecate direct `nodemap` access...
r43974 def _nodemap(self):
revlogutils: move the NodeMap class in a dedicated nodemap module...
r44486 nodemap = nodemaputil.NodeMap({nullid: nullrev})
revlog: move the nodemap into the index object (for pure)...
r43925 for r in range(0, len(self)):
n = self[r][7]
nodemap[n] = r
return nodemap
index: add a `has_node` method (API)...
r43934 def has_node(self, node):
"""return True if the node exist in the index"""
revlog: deprecate direct `nodemap` access...
r43974 return node in self._nodemap
index: add a `has_node` method (API)...
r43934
index: add a `rev` method (API)...
r43952 def rev(self, node):
"""return a revision for a node
If the node is unknown, raise a RevlogError"""
revlog: deprecate direct `nodemap` access...
r43974 return self._nodemap[node]
index: add a `rev` method (API)...
r43952
index: add a `get_rev` method (API)...
r43954 def get_rev(self, node):
"""return a revision for a node
If the node is unknown, return None"""
revlog: deprecate direct `nodemap` access...
r43974 return self._nodemap.get(node)
index: add a `get_rev` method (API)...
r43954
revlog: deal with nodemap deletion within the index...
r43933 def _stripnodes(self, start):
revlog: deprecate direct `nodemap` access...
r43974 if '_nodemap' in vars(self):
revlog: deal with nodemap deletion within the index...
r43933 for r in range(start, len(self)):
n = self[r][7]
revlog: deprecate direct `nodemap` access...
r43974 del self._nodemap[n]
revlog: deal with nodemap deletion within the index...
r43933
revlog: move the nodemap into the index object (for pure)...
r43925 def clearcaches(self):
revlog: deprecate direct `nodemap` access...
r43974 self.__dict__.pop('_nodemap', None)
revlog: move the nodemap into the index object (for pure)...
r43925
Maciej Fijalkowski
pure: write a really lazy version of pure indexObject...
r29133 def __len__(self):
Martin von Zweigbergk
index: don't include nullid in len()...
r38887 return self._lgt + len(self._extra)
Maciej Fijalkowski
pure: write a really lazy version of pure indexObject...
r29133
Martin von Zweigbergk
index: replace insert(-1, e) method by append(e) method...
r38886 def append(self, tup):
revlog: deprecate direct `nodemap` access...
r43974 if '_nodemap' in vars(self):
self._nodemap[tup[7]] = len(self)
revlog: directly use the Struct object for related operation...
r47619 data = self.index_format.pack(*tup)
Joerg Sonnenberger
revlog: store new index entries as binary...
r46548 self._extra.append(data)
Matt Mackall
pure/parsers: fix circular imports, import mercurial modules properly
r7945
Martin von Zweigbergk
index: rename _fix_index() since it no longer fixes the index...
r39251 def _check_index(self, i):
Maciej Fijalkowski
pure: write a really lazy version of pure indexObject...
r29133 if not isinstance(i, int):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise TypeError(b"expecting int indexes")
Martin von Zweigbergk
index: don't include nullid in boundary check in pure code...
r39250 if i < 0 or i >= len(self):
Maciej Fijalkowski
pure: write a really lazy version of pure indexObject...
r29133 raise IndexError
Matt Mackall
pure/parsers: fix circular imports, import mercurial modules properly
r7945
Maciej Fijalkowski
pure: write a really lazy version of pure indexObject...
r29133 def __getitem__(self, i):
Augie Fackler
parsers: adjust pure-python version to mimic a3dacabd476b...
r39082 if i == -1:
Raphaël Gomès
revlog: prepare pure parser for being overloaded...
r47136 return self.null_item
Martin von Zweigbergk
index: rename _fix_index() since it no longer fixes the index...
r39251 self._check_index(i)
Maciej Fijalkowski
pure: write a really lazy version of pure indexObject...
r29133 if i >= self._lgt:
Joerg Sonnenberger
revlog: store new index entries as binary...
r46548 data = self._extra[i - self._lgt]
else:
index = self._calculate_index(i)
Raphaël Gomès
revlog: prepare pure parser for being overloaded...
r47136 data = self._data[index : index + self.index_size]
revlog: directly use the Struct object for related operation...
r47619 r = self.index_format.unpack(data)
Joerg Sonnenberger
revlog: store new index entries as binary...
r46548 if self._lgt and i == 0:
r = (offset_type(0, gettype(r[0])),) + r[1:]
Maciej Fijalkowski
pure: write a really lazy version of pure indexObject...
r29133 return r
Augie Fackler
formatting: blacken the codebase...
r43346
Maciej Fijalkowski
pure: write a really lazy version of pure indexObject...
r29133 class IndexObject(BaseIndexObject):
def __init__(self, data):
Raphaël Gomès
revlog: prepare pure parser for being overloaded...
r47136 assert len(data) % self.index_size == 0
Maciej Fijalkowski
pure: write a really lazy version of pure indexObject...
r29133 self._data = data
Raphaël Gomès
revlog: prepare pure parser for being overloaded...
r47136 self._lgt = len(data) // self.index_size
Maciej Fijalkowski
pure: write a really lazy version of pure indexObject...
r29133 self._extra = []
def _calculate_index(self, i):
Raphaël Gomès
revlog: prepare pure parser for being overloaded...
r47136 return i * self.index_size
Matt Mackall
revlog: remove lazy index
r13253
Maciej Fijalkowski
pure: write a really lazy version of pure indexObject...
r29133 def __delitem__(self, i):
Alex Gaynor
style: always use `x is not None` instead of `not x is None`...
r34332 if not isinstance(i, slice) or not i.stop == -1 or i.step is not None:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise ValueError(b"deleting slices only supports a:-1 with step 1")
Martin von Zweigbergk
index: rename _fix_index() since it no longer fixes the index...
r39251 i = i.start
self._check_index(i)
revlog: deal with nodemap deletion within the index...
r43933 self._stripnodes(i)
Maciej Fijalkowski
pure: write a really lazy version of pure indexObject...
r29133 if i < self._lgt:
Raphaël Gomès
revlog: prepare pure parser for being overloaded...
r47136 self._data = self._data[: i * self.index_size]
Maciej Fijalkowski
pure: write a really lazy version of pure indexObject...
r29133 self._lgt = i
self._extra = []
else:
Augie Fackler
formatting: blacken the codebase...
r43346 self._extra = self._extra[: i - self._lgt]
Maciej Fijalkowski
pure: write a really lazy version of pure indexObject...
r29133
nodemap: add a (python) index class for persistent nodemap testing...
r44794 class PersistentNodeMapIndexObject(IndexObject):
"""a Debug oriented class to test persistent nodemap
We need a simple python object to test API and higher level behavior. See
the Rust implementation for more serious usage. This should be used only
through the dedicated `devel.persistent-nodemap` config.
"""
nodemap: add a optional `nodemap_add_full` method on indexes...
r44795 def nodemap_data_all(self):
"""Return bytes containing a full serialization of a nodemap
The nodemap should be valid for the full set of revisions in the
index."""
return nodemaputil.persistent_data(self)
nodemap: introduce append-only incremental update of the persistent data...
r44805 def nodemap_data_incremental(self):
"""Return bytes containing a incremental update to persistent nodemap
This containst the data for an append-only update of the data provided
in the last call to `update_nodemap_data`.
"""
if self._nm_root is None:
return None
nodemap: double check the source docket when doing incremental update...
r44809 docket = self._nm_docket
nodemap: track the total and unused amount of data in the rawdata file...
r44808 changed, data = nodemaputil.update_persistent_data(
nodemap: double check the source docket when doing incremental update...
r44809 self, self._nm_root, self._nm_max_idx, self._nm_docket.tip_rev
nodemap: introduce append-only incremental update of the persistent data...
r44805 )
nodemap: double check the source docket when doing incremental update...
r44809
self._nm_root = self._nm_max_idx = self._nm_docket = None
return docket, changed, data
nodemap: introduce append-only incremental update of the persistent data...
r44805
nodemap: track the maximum revision tracked in the nodemap...
r44807 def update_nodemap_data(self, docket, nm_data):
"""provide full block of persisted binary data for a nodemap
nodemap: provide the on disk data to indexes who support it...
r44801
The data are expected to come from disk. See `nodemap_data_all` for a
produceur of such data."""
if nm_data is not None:
nodemap: introduce append-only incremental update of the persistent data...
r44805 self._nm_root, self._nm_max_idx = nodemaputil.parse_data(nm_data)
if self._nm_root:
nodemap: double check the source docket when doing incremental update...
r44809 self._nm_docket = docket
nodemap: introduce append-only incremental update of the persistent data...
r44805 else:
nodemap: double check the source docket when doing incremental update...
r44809 self._nm_root = self._nm_max_idx = self._nm_docket = None
nodemap: provide the on disk data to indexes who support it...
r44801
nodemap: add a (python) index class for persistent nodemap testing...
r44794
Maciej Fijalkowski
pure: write a really lazy version of pure indexObject...
r29133 class InlinedIndexObject(BaseIndexObject):
def __init__(self, data, inline=0):
self._data = data
self._lgt = self._inline_scan(None)
self._inline_scan(self._lgt)
self._extra = []
Martin Geisler
pure Python implementation of parsers.c
r7700
Maciej Fijalkowski
pure: write a really lazy version of pure indexObject...
r29133 def _inline_scan(self, lgt):
off = 0
if lgt is not None:
self._offsets = [0] * lgt
count = 0
Raphaël Gomès
revlog: prepare pure parser for being overloaded...
r47136 while off <= len(self._data) - self.index_size:
start = off + self.big_int_size
Augie Fackler
formatting: blacken the codebase...
r43346 (s,) = struct.unpack(
Raphaël Gomès
revlog: prepare pure parser for being overloaded...
r47136 b'>i',
self._data[start : start + self.int_size],
Augie Fackler
formatting: blacken the codebase...
r43346 )
Maciej Fijalkowski
pure: write a really lazy version of pure indexObject...
r29133 if lgt is not None:
self._offsets[count] = off
count += 1
Raphaël Gomès
revlog: prepare pure parser for being overloaded...
r47136 off += self.index_size + s
Maciej Fijalkowski
pure: write a really lazy version of pure indexObject...
r29133 if off != len(self._data):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise ValueError(b"corrupted data")
Maciej Fijalkowski
pure: write a really lazy version of pure indexObject...
r29133 return count
Augie Fackler
pure parsers: properly detect corrupt index files...
r14421
Maciej Fijalkowski
pure: write a really lazy version of pure indexObject...
r29133 def __delitem__(self, i):
Alex Gaynor
style: always use `x is not None` instead of `not x is None`...
r34332 if not isinstance(i, slice) or not i.stop == -1 or i.step is not None:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise ValueError(b"deleting slices only supports a:-1 with step 1")
Martin von Zweigbergk
index: rename _fix_index() since it no longer fixes the index...
r39251 i = i.start
self._check_index(i)
revlog: deal with nodemap deletion within the index...
r43933 self._stripnodes(i)
Maciej Fijalkowski
pure: write a really lazy version of pure indexObject...
r29133 if i < self._lgt:
self._offsets = self._offsets[:i]
self._lgt = i
self._extra = []
else:
Augie Fackler
formatting: blacken the codebase...
r43346 self._extra = self._extra[: i - self._lgt]
Martin Geisler
pure Python implementation of parsers.c
r7700
Maciej Fijalkowski
pure: write a really lazy version of pure indexObject...
r29133 def _calculate_index(self, i):
return self._offsets[i]
Martin Geisler
pure Python implementation of parsers.c
r7700
Augie Fackler
formatting: blacken the codebase...
r43346
Raphaël Gomès
revlog: introduce v2 format...
r47438 def parse_index2(data, inline, revlogv2=False):
Maciej Fijalkowski
pure: write a really lazy version of pure indexObject...
r29133 if not inline:
Raphaël Gomès
revlog: introduce v2 format...
r47438 cls = IndexObject2 if revlogv2 else IndexObject
return cls(data), None
cls = InlinedIndexObject2 if revlogv2 else InlinedIndexObject
return cls(data, inline), (0, data)
class Index2Mixin(object):
revlog: directly use the Struct object for related operation...
r47619 index_format = revlog_constants.INDEX_ENTRY_V2
revlog: move the details of revlog "v2" index inside revlog.utils.constants...
r47617 index_size = revlog_constants.INDEX_ENTRY_V2.size
Raphaël Gomès
revlog: introduce v2 format...
r47438 null_item = (0, 0, 0, -1, -1, -1, -1, nullid, 0, 0)
Raphaël Gomès
revlog-index: add `replace_sidedata_info` method...
r47451 def replace_sidedata_info(self, i, sidedata_offset, sidedata_length):
"""
Replace an existing index entry's sidedata offset and length with new
ones.
This cannot be used outside of the context of sidedata rewriting,
inside the transaction that creates the revision `i`.
"""
if i < 0:
raise KeyError
self._check_index(i)
sidedata_format = b">Qi"
packed_size = struct.calcsize(sidedata_format)
if i >= self._lgt:
packed = _pack(sidedata_format, sidedata_offset, sidedata_length)
old = self._extra[i - self._lgt]
new = old[:64] + packed + old[64 + packed_size :]
self._extra[i - self._lgt] = new
else:
msg = b"cannot rewrite entries outside of this transaction"
raise KeyError(msg)
Raphaël Gomès
revlog: introduce v2 format...
r47438
class IndexObject2(Index2Mixin, IndexObject):
pass
class InlinedIndexObject2(Index2Mixin, InlinedIndexObject):
def _inline_scan(self, lgt):
sidedata_length_pos = 72
off = 0
if lgt is not None:
self._offsets = [0] * lgt
count = 0
while off <= len(self._data) - self.index_size:
start = off + self.big_int_size
(data_size,) = struct.unpack(
b'>i',
self._data[start : start + self.int_size],
)
start = off + sidedata_length_pos
(side_data_size,) = struct.unpack(
b'>i', self._data[start : start + self.int_size]
)
if lgt is not None:
self._offsets[count] = off
count += 1
off += self.index_size + data_size + side_data_size
if off != len(self._data):
raise ValueError(b"corrupted data")
return count
Martin Geisler
pure Python implementation of parsers.c
r7700
Augie Fackler
formatting: blacken the codebase...
r43346
nodemap: add a (python) index class for persistent nodemap testing...
r44794 def parse_index_devel_nodemap(data, inline):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """like parse_index2, but alway return a PersistentNodeMapIndexObject"""
nodemap: add a (python) index class for persistent nodemap testing...
r44794 return PersistentNodeMapIndexObject(data), None
Martin Geisler
pure Python implementation of parsers.c
r7700 def parse_dirstate(dmap, copymap, st):
Augie Fackler
formatting: blacken the codebase...
r43346 parents = [st[:20], st[20:40]]
Mads Kiilerich
fix wording and not-completely-trivial spelling errors and bad docstrings
r17425 # dereference fields so they will be local in loop
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 format = b">cllll"
Matt Mackall
pure/parsers: fix circular imports, import mercurial modules properly
r7945 e_size = struct.calcsize(format)
Martin Geisler
pure Python implementation of parsers.c
r7700 pos1 = 40
l = len(st)
# the inner loop
while pos1 < l:
pos2 = pos1 + e_size
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 e = _unpack(b">cllll", st[pos1:pos2]) # a literal here is faster
Martin Geisler
pure Python implementation of parsers.c
r7700 pos1 = pos2 + e[4]
f = st[pos2:pos1]
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if b'\0' in f:
f, c = f.split(b'\0')
Martin Geisler
pure Python implementation of parsers.c
r7700 copymap[f] = c
dmap[f] = e[:4]
return parents
Siddharth Agarwal
dirstate: move pure python dirstate packing to pure/parsers.py
r18567
Augie Fackler
formatting: blacken the codebase...
r43346
Siddharth Agarwal
dirstate: move pure python dirstate packing to pure/parsers.py
r18567 def pack_dirstate(dmap, copymap, pl, now):
now = int(now)
timeless
pycompat: switch to util.stringio for py3 compat
r28861 cs = stringio()
Siddharth Agarwal
dirstate: move pure python dirstate packing to pure/parsers.py
r18567 write = cs.write
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 write(b"".join(pl))
Gregory Szorc
py3: finish porting iteritems() to pycompat and remove source transformer...
r43376 for f, e in pycompat.iteritems(dmap):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if e[0] == b'n' and e[3] == now:
Siddharth Agarwal
dirstate: move pure python dirstate packing to pure/parsers.py
r18567 # The file was last modified "simultaneously" with the current
# write to dirstate (i.e. within the same second for file-
# systems with a granularity of 1 sec). This commonly happens
# for at least a couple of files on 'update'.
# The user could change the file without changing its size
Siddharth Agarwal
pack_dirstate: only invalidate mtime for files written in the last second...
r19652 # within the same second. Invalidate the file's mtime in
Siddharth Agarwal
dirstate: move pure python dirstate packing to pure/parsers.py
r18567 # dirstate, forcing future 'status' calls to compare the
Siddharth Agarwal
pack_dirstate: only invalidate mtime for files written in the last second...
r19652 # contents of the file if the size is the same. This prevents
# mistakenly treating such files as clean.
Siddharth Agarwal
parsers: inline fields of dirstate values in C version...
r21809 e = dirstatetuple(e[0], e[1], e[2], -1)
Siddharth Agarwal
dirstate: move pure python dirstate packing to pure/parsers.py
r18567 dmap[f] = e
if f in copymap:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 f = b"%s\0%s" % (f, copymap[f])
e = _pack(b">cllll", e[0], e[1], e[2], e[3], len(f))
Siddharth Agarwal
dirstate: move pure python dirstate packing to pure/parsers.py
r18567 write(e)
write(f)
return cs.getvalue()