##// END OF EJS Templates
pytype: use "$(hg root)" instead of `hg root` to make shellcheck happier
pytype: use "$(hg root)" instead of `hg root` to make shellcheck happier

File last commit:

r52074:dcaa2df1 default
r52199:46280260 default
Show More
changelog.py
506 lines | 15.9 KiB | text/x-python | PythonLexer
mpm@selenic.com
changelog: adjust imports, comment
r1095 # changelog.py - changelog class for mercurial
mpm@selenic.com
Break apart hg.py...
r1089 #
Raphaël Gomès
contributor: change mentions of mpm to olivia...
r47575 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
mpm@selenic.com
Break apart hg.py...
r1089 #
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.
mpm@selenic.com
Break apart hg.py...
r1089
Gregory Szorc
changelog: use absolute_import
r25922
from .i18n import _
from .node import (
bin,
hex,
)
Augie Fackler
formatting: blacken the codebase...
r43346 from .thirdparty import attr
Gregory Szorc
changelog: use absolute_import
r25922
from . import (
encoding,
error,
metadata: move computation related to files touched in a dedicated module...
r45466 metadata,
Pulkit Goyal
py3: use pycompat.bytestr to convert str to bytes...
r36246 pycompat,
Gregory Szorc
changelog: use absolute_import
r25922 revlog,
)
Yuya Nishihara
stringutil: bulk-replace call sites to point to new module...
r37102 from .utils import (
dateutil,
stringutil,
)
revlog: introduce an explicit tracking of what the revlog is about...
r47838 from .revlogutils import (
constants as revlog_constants,
flagutil,
)
mpm@selenic.com
Break apart hg.py...
r1089
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _defaultextra = {b'branch': b'default'}
Matt Mackall
changelog: micro-optimizations to changelog.read()
r16267
Augie Fackler
formatting: blacken the codebase...
r43346
Benoit Boissinot
[extendedchangelog] encode/decode function...
r3232 def _string_escape(text):
"""
Yuya Nishihara
doctest: replace chr() with pycompat.bytechr()
r34135 >>> from .pycompat import bytechr as chr
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> d = {b'nl': chr(10), b'bs': chr(92), b'cr': chr(13), b'nul': chr(0)}
Martin von Zweigbergk
changelog: extract a _string_unescape() to mirror _string_escape()...
r42285 >>> s = b"ab%(nl)scd%(bs)s%(bs)sn%(nul)s12ab%(cr)scd%(bs)s%(nl)s" % d
Benoit Boissinot
[extendedchangelog] encode/decode function...
r3232 >>> s
Martin von Zweigbergk
changelog: extract a _string_unescape() to mirror _string_escape()...
r42285 'ab\\ncd\\\\\\\\n\\x0012ab\\rcd\\\\\\n'
Benoit Boissinot
[extendedchangelog] encode/decode function...
r3232 >>> res = _string_escape(s)
Martin von Zweigbergk
changelog: extract a _string_unescape() to mirror _string_escape()...
r42285 >>> s == _string_unescape(res)
Benoit Boissinot
[extendedchangelog] encode/decode function...
r3232 True
"""
# subset of the string_escape codec
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 text = (
text.replace(b'\\', b'\\\\')
.replace(b'\n', b'\\n')
.replace(b'\r', b'\\r')
)
return text.replace(b'\0', b'\\0')
Benoit Boissinot
[extendedchangelog] encode/decode function...
r3232
Augie Fackler
formatting: blacken the codebase...
r43346
Martin von Zweigbergk
changelog: extract a _string_unescape() to mirror _string_escape()...
r42285 def _string_unescape(text):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if b'\\0' in text:
Martin von Zweigbergk
changelog: extract a _string_unescape() to mirror _string_escape()...
r42285 # fix up \0 without getting into trouble with \\0
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 text = text.replace(b'\\\\', b'\\\\\n')
text = text.replace(b'\\0', b'\0')
text = text.replace(b'\n', b'')
Martin von Zweigbergk
changelog: extract a _string_unescape() to mirror _string_escape()...
r42285 return stringutil.unescapestr(text)
Augie Fackler
formatting: blacken the codebase...
r43346
Martin Geisler
changelog: turn {de,en}code_extra methods into functions...
r8443 def decodeextra(text):
Matt Mackall
changelog: handle decoding of NULs in extra more carefully (issue3156)...
r15661 """
Yuya Nishihara
doctest: replace chr() with pycompat.bytechr()
r34135 >>> from .pycompat import bytechr as chr
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> sorted(decodeextra(encodeextra({b'foo': b'bar', b'baz': chr(0) + b'2'})
Yuya Nishihara
doctest: replace .iteritems() with .items()
r34134 ... ).items())
Mads Kiilerich
tests: fix doctest stability over Python versions...
r18379 [('baz', '\\x002'), ('branch', 'default'), ('foo', 'bar')]
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> sorted(decodeextra(encodeextra({b'foo': b'bar',
... b'baz': chr(92) + chr(0) + b'2'})
Yuya Nishihara
doctest: replace .iteritems() with .items()
r34134 ... ).items())
Mads Kiilerich
tests: fix doctest stability over Python versions...
r18379 [('baz', '\\\\\\x002'), ('branch', 'default'), ('foo', 'bar')]
Matt Mackall
changelog: handle decoding of NULs in extra more carefully (issue3156)...
r15661 """
Matt Mackall
changelog: micro-optimizations to changelog.read()
r16267 extra = _defaultextra.copy()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 for l in text.split(b'\0'):
Martin Geisler
changelog: turn {de,en}code_extra methods into functions...
r8443 if l:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 k, v = _string_unescape(l).split(b':', 1)
Martin Geisler
changelog: turn {de,en}code_extra methods into functions...
r8443 extra[k] = v
return extra
Augie Fackler
formatting: blacken the codebase...
r43346
Martin Geisler
changelog: turn {de,en}code_extra methods into functions...
r8443 def encodeextra(d):
# keys must be sorted to produce a deterministic changelog entry
Martin von Zweigbergk
py3: require values in changelog extras to be bytes...
r45095 items = [_string_escape(b'%s:%s' % (k, d[k])) for k in sorted(d)]
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return b"\0".join(items)
Martin Geisler
changelog: turn {de,en}code_extra methods into functions...
r8443
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
changelog: extract description cleaning logic in a dedicated function...
r17810 def stripdesc(desc):
"""strip trailing whitespace and leading and trailing empty lines"""
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return b'\n'.join([l.rstrip() for l in desc.splitlines()]).strip(b'\n')
Pierre-Yves David
changelog: extract description cleaning logic in a dedicated function...
r17810
Augie Fackler
formatting: blacken the codebase...
r43346
Siddharth Agarwal
changelog: use attrs instead of namedtuple...
r34399 @attr.s
Gregory Szorc
py3: use class X: instead of class X(object):...
r49801 class _changelogrevision:
Siddharth Agarwal
changelog: use attrs instead of namedtuple...
r34399 # Extensions might modify _defaultextra, so let the constructor below pass
# it in
extra = attr.ib()
Joerg Sonnenberger
node: introduce nodeconstants class...
r47538 manifest = attr.ib()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 user = attr.ib(default=b'')
Siddharth Agarwal
changelog: use attrs instead of namedtuple...
r34399 date = attr.ib(default=(0, 0))
Gregory Szorc
changelog: use a Factory for default value for files...
r34442 files = attr.ib(default=attr.Factory(list))
Martin von Zweigbergk
context: get filesadded() and filesremoved() from changeset if configured...
r42599 filesadded = attr.ib(default=None)
filesremoved = attr.ib(default=None)
Martin von Zweigbergk
changelog: define changelogrevision.p[12]copies for null revision...
r42487 p1copies = attr.ib(default=None)
p2copies = attr.ib(default=None)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 description = attr.ib(default=b'')
Joerg Sonnenberger
changelog: move branchinfo to changelogrevision...
r47082 branchinfo = attr.ib(default=(_defaultextra[b'branch'], False))
Gregory Szorc
changelog: add class to represent parsed changelog revisions...
r28487
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
py3: use class X: instead of class X(object):...
r49801 class changelogrevision:
Gregory Szorc
changelog: add class to represent parsed changelog revisions...
r28487 """Holds results of a parsed changelog revision.
Changelog revisions consist of multiple pieces of data, including
the manifest node, user, and date. This object exposes a view into
the parsed object.
"""
__slots__ = (
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 '_offsets',
'_text',
'_sidedata',
'_cpsd',
changelog: add a `changes` property on `changelogrevision`...
r46144 '_changes',
Gregory Szorc
changelog: add class to represent parsed changelog revisions...
r28487 )
Joerg Sonnenberger
node: introduce nodeconstants class...
r47538 def __new__(cls, cl, text, sidedata, cpsd):
Gregory Szorc
changelog: add class to represent parsed changelog revisions...
r28487 if not text:
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 return _changelogrevision(extra=_defaultextra, manifest=cl.nullid)
Gregory Szorc
changelog: add class to represent parsed changelog revisions...
r28487
self = super(changelogrevision, cls).__new__(cls)
# We could return here and implement the following as an __init__.
# But doing it here is equivalent and saves an extra function call.
# format used:
# nodeid\n : manifest node in ascii
# user\n : user, no \n or \r allowed
# time tz extra\n : date (time is int or float, timezone is int)
# : extra is metadata, encoded and separated by '\0'
# : older versions ignore it
# files\n\n : files modified by the cset, no \n or \r allowed
# (.*) : comment (free text, ideally utf-8)
#
# changelog v0 doesn't use extra
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 nl1 = text.index(b'\n')
nl2 = text.index(b'\n', nl1 + 1)
nl3 = text.index(b'\n', nl2 + 1)
Gregory Szorc
changelog: add class to represent parsed changelog revisions...
r28487
Gregory Szorc
changelog: lazily parse files...
r28493 # The list of files may be empty. Which means nl3 is the first of the
# double newline that precedes the description.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if text[nl3 + 1 : nl3 + 2] == b'\n':
Gregory Szorc
changelog: avoid slicing raw data until needed...
r28495 doublenl = nl3
Gregory Szorc
changelog: lazily parse files...
r28493 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 doublenl = text.index(b'\n\n', nl3 + 1)
Gregory Szorc
changelog: avoid slicing raw data until needed...
r28495
self._offsets = (nl1, nl2, nl3, doublenl)
self._text = text
sidedatacopies: get and store sidedata in the changelogrevision object...
r43413 self._sidedata = sidedata
sidedatacopies: only read from copies when in this mode...
r43504 self._cpsd = cpsd
changelog: add a `changes` property on `changelogrevision`...
r46144 self._changes = None
Gregory Szorc
changelog: add class to represent parsed changelog revisions...
r28487
return self
Gregory Szorc
changelog: lazily parse description...
r28489 @property
Gregory Szorc
changelog: lazily parse manifest node...
r28490 def manifest(self):
Augie Fackler
formatting: blacken the codebase...
r43346 return bin(self._text[0 : self._offsets[0]])
Gregory Szorc
changelog: lazily parse manifest node...
r28490
@property
Gregory Szorc
changelog: lazily parse user...
r28491 def user(self):
Gregory Szorc
changelog: avoid slicing raw data until needed...
r28495 off = self._offsets
Augie Fackler
formatting: blacken the codebase...
r43346 return encoding.tolocal(self._text[off[0] + 1 : off[1]])
Gregory Szorc
changelog: lazily parse user...
r28491
@property
Gregory Szorc
changelog: lazily parse date/extra field...
r28492 def _rawdate(self):
Gregory Szorc
changelog: avoid slicing raw data until needed...
r28495 off = self._offsets
Augie Fackler
formatting: blacken the codebase...
r43346 dateextra = self._text[off[1] + 1 : off[2]]
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return dateextra.split(b' ', 2)[0:2]
Gregory Szorc
changelog: lazily parse date/extra field...
r28492
@property
def _rawextra(self):
Gregory Szorc
changelog: avoid slicing raw data until needed...
r28495 off = self._offsets
Augie Fackler
formatting: blacken the codebase...
r43346 dateextra = self._text[off[1] + 1 : off[2]]
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 fields = dateextra.split(b' ', 2)
Gregory Szorc
changelog: lazily parse date/extra field...
r28492 if len(fields) != 3:
return None
return fields[2]
@property
def date(self):
raw = self._rawdate
time = float(raw[0])
# Various tools did silly things with the timezone.
try:
timezone = int(raw[1])
except ValueError:
timezone = 0
return time, timezone
@property
def extra(self):
raw = self._rawextra
if raw is None:
return _defaultextra
return decodeextra(raw)
@property
changelog: add a `changes` property on `changelogrevision`...
r46144 def changes(self):
if self._changes is not None:
return self._changes
sidedata: add a `decode_files_sidedata` function...
r46145 if self._cpsd:
changing-files: drop the now useless changelogrevision argument...
r46212 changes = metadata.decode_files_sidedata(self._sidedata)
sidedata: add a `decode_files_sidedata` function...
r46145 else:
changes = metadata.ChangingFiles(
touched=self.files or (),
added=self.filesadded or (),
removed=self.filesremoved or (),
p1_copies=self.p1copies or {},
p2_copies=self.p2copies or {},
)
changelog: add a `changes` property on `changelogrevision`...
r46144 self._changes = changes
return changes
@property
Gregory Szorc
changelog: lazily parse files...
r28493 def files(self):
changing-files: retrieve changelogrevision.files from the sidedata block...
r46213 if self._cpsd:
return sorted(self.changes.touched)
Gregory Szorc
changelog: avoid slicing raw data until needed...
r28495 off = self._offsets
if off[2] == off[3]:
Gregory Szorc
changelog: lazily parse files...
r28493 return []
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return self._text[off[2] + 1 : off[3]].split(b'\n')
Gregory Szorc
changelog: lazily parse files...
r28493
@property
Martin von Zweigbergk
context: get filesadded() and filesremoved() from changeset if configured...
r42599 def filesadded(self):
sidedatacopies: only read from copies when in this mode...
r43504 if self._cpsd:
sidedata: simply read added files from the `ChangingFiles` object
r46146 return self.changes.added
sidedatacopies: read rename information from sidedata...
r43416 else:
rawindices = self.extra.get(b'filesadded')
changelog: make copies related function return None or a valid value...
r43415 if rawindices is None:
return None
metadata: move computation related to files touched in a dedicated module...
r45466 return metadata.decodefileindices(self.files, rawindices)
Martin von Zweigbergk
context: get filesadded() and filesremoved() from changeset if configured...
r42599
@property
def filesremoved(self):
sidedatacopies: only read from copies when in this mode...
r43504 if self._cpsd:
sidedata: simply read removed files from the `ChangingFiles` object
r46147 return self.changes.removed
sidedatacopies: read rename information from sidedata...
r43416 else:
rawindices = self.extra.get(b'filesremoved')
changelog: make copies related function return None or a valid value...
r43415 if rawindices is None:
return None
metadata: move computation related to files touched in a dedicated module...
r45466 return metadata.decodefileindices(self.files, rawindices)
Martin von Zweigbergk
context: get filesadded() and filesremoved() from changeset if configured...
r42599
@property
Martin von Zweigbergk
changelog: parse copy metadata if available in extras...
r42318 def p1copies(self):
sidedatacopies: only read from copies when in this mode...
r43504 if self._cpsd:
sidedata: simply read p1copies files from the `ChangingFiles` object
r46148 return self.changes.copied_from_p1
sidedatacopies: read rename information from sidedata...
r43416 else:
rawcopies = self.extra.get(b'p1copies')
changelog: make copies related function return None or a valid value...
r43415 if rawcopies is None:
return None
metadata: move computation related to files touched in a dedicated module...
r45466 return metadata.decodecopies(self.files, rawcopies)
Martin von Zweigbergk
changelog: parse copy metadata if available in extras...
r42318
@property
def p2copies(self):
sidedatacopies: only read from copies when in this mode...
r43504 if self._cpsd:
sidedata: simply read p2copies files from the `ChangingFiles` object
r46149 return self.changes.copied_from_p2
sidedatacopies: read rename information from sidedata...
r43416 else:
rawcopies = self.extra.get(b'p2copies')
changelog: make copies related function return None or a valid value...
r43415 if rawcopies is None:
return None
metadata: move computation related to files touched in a dedicated module...
r45466 return metadata.decodecopies(self.files, rawcopies)
Martin von Zweigbergk
changelog: parse copy metadata if available in extras...
r42318
@property
Gregory Szorc
changelog: lazily parse description...
r28489 def description(self):
Augie Fackler
formatting: blacken the codebase...
r43346 return encoding.tolocal(self._text[self._offsets[3] + 2 :])
Joerg Sonnenberger
changelog: move branchinfo to changelogrevision...
r47082 @property
def branchinfo(self):
extra = self.extra
return encoding.tolocal(extra.get(b"branch")), b'close' in extra
Gregory Szorc
changelog: lazily parse description...
r28489
Matt Mackall
revlog: kill from-style imports...
r7634 class changelog(revlog.revlog):
Kyle Lippincott
revlog: add a mechanism to verify expected file position before appending...
r47349 def __init__(self, opener, trypending=False, concurrencychecker=None):
Gregory Szorc
changelog: load pending file directly...
r32292 """Load a changelog revlog using an opener.
If ``trypending`` is true, we attempt to load the index from a
``00changelog.i.a`` file instead of the default ``00changelog.i``.
The ``00changelog.i.a`` file contains index (and possibly inline
revision) data for a transaction that hasn't been finalized yet.
It exists in a separate file to facilitate readers (such as
hooks processes) accessing data before a transaction is finalized.
Kyle Lippincott
revlog: add a mechanism to verify expected file position before appending...
r47349
``concurrencychecker`` will be passed to the revlog init function, see
the documentation there.
Gregory Szorc
changelog: load pending file directly...
r32292 """
Augie Fackler
formatting: blacken the codebase...
r43346 revlog.revlog.__init__(
self,
opener,
revlog: introduce an explicit tracking of what the revlog is about...
r47838 target=(revlog_constants.KIND_CHANGELOG, None),
revlog: use a "radix" to address revlog...
r47921 radix=b'00changelog',
Augie Fackler
formatting: blacken the codebase...
r43346 checkambig=True,
mmaplargeindex=True,
nodemap: drop the 'exp-' prefix for internal opener option...
r45296 persistentnodemap=opener.options.get(b'persistent-nodemap', False),
Kyle Lippincott
revlog: add a mechanism to verify expected file position before appending...
r47349 concurrencychecker=concurrencychecker,
revlog: move the `trypending` logic from the `changelog` to the `revlog`...
r48014 trypending=trypending,
changelog: never inline changelog...
r52074 may_inline=False,
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
changelog: load pending file directly...
r32292
revlog: split the `version` attribute into its two components...
r47910 if self._initempty and (self._format_version == revlog.REVLOGV1):
Gregory Szorc
revlog: always enable generaldelta on version 2 revlogs...
r41238 # changelogs don't benefit from generaldelta.
revlog: split the `version` attribute into its two components...
r47910 self._format_flags &= ~revlog.FLAG_GENERALDELTA
revlog: move configuration attribute into dedicated object...
r51922 self.delta_config.general_delta = False
Gregory Szorc
changelog: disable delta chains...
r30155
# Delta chains for changelogs tend to be very small because entries
# tend to be small and don't delta well with each. So disable delta
# chains.
Gregory Szorc
repository: remove storedeltachains from ifilestorage...
r39268 self._storedeltachains = False
Gregory Szorc
changelog: disable delta chains...
r30155
changelog-delay: move the delay/divert logic inside the (inner) revlog...
r51999 self._v2_delayed = False
Kyle Lippincott
branchmap: add a cache validation cache, avoid expensive re-hash on every use...
r46088 self._filteredrevs = frozenset()
self._filteredrevs_hashcache = {}
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self._copiesstorage = opener.options.get(b'copies-storage')
Pierre-Yves David
clfilter: introduce `filteredrevs` attribute on changelog...
r17677
Kyle Lippincott
branchmap: add a cache validation cache, avoid expensive re-hash on every use...
r46088 @property
def filteredrevs(self):
return self._filteredrevs
@filteredrevs.setter
def filteredrevs(self, val):
# Ensure all updates go through this function
assert isinstance(val, frozenset)
self._filteredrevs = val
self._filteredrevs_hashcache = {}
revlogv2: delay the update of the changelog docket to transaction end...
r48013 def _write_docket(self, tr):
changelog-delay: move the delay/divert logic inside the (inner) revlog...
r51999 if not self._v2_delayed:
revlogv2: delay the update of the changelog docket to transaction end...
r48013 super(changelog, self)._write_docket(tr)
Pierre-Yves David
changelog: handle writepending in the transaction...
r23203 def delayupdate(self, tr):
Matt Harbison
cleanup: fix docstring formatting...
r44226 """delay visibility of index updates to other readers"""
changelog-delay: adds some check around delaying and diverting write...
r51995 assert not self._inner.is_open
changelog: never inline changelog...
r52074 assert not self._may_inline
# enforce that older changelog that are still inline are split at the
# first opportunity.
if self._inline:
self._enforceinlinesize(tr)
changelog-delay: move the delay/divert logic inside the (inner) revlog...
r51999 if self._docket is not None:
self._v2_delayed = True
else:
new_index = self._inner.delay()
if new_index is not None:
self._indexfile = new_index
tr.registertmp(new_index)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 tr.addpending(b'cl-%i' % id(self), self._writepending)
tr.addfinalize(b'cl-%i' % id(self), self._finalize)
Matt Mackall
restructure changelog file appending...
r4261
Pierre-Yves David
changelog: rely on transaction for finalization...
r23205 def _finalize(self, tr):
Matt Harbison
cleanup: fix docstring formatting...
r44226 """finalize index updates"""
changelog-delay: adds some check around delaying and diverting write...
r51995 assert not self._inner.is_open
revlogv2: delay the update of the changelog docket to transaction end...
r48013 if self._docket is not None:
changelog-delay: move the delay/divert logic inside the (inner) revlog...
r51999 self._docket.write(tr)
self._v2_delayed = False
else:
new_index_file = self._inner.finalize_pending()
self._indexfile = new_index_file
# split when we're done
self._enforceinlinesize(tr, side_write=False)
Matt Mackall
restructure changelog file appending...
r4261
Pierre-Yves David
transaction: pass the transaction to 'pending' callback...
r23280 def _writepending(self, tr):
Matt Harbison
cleanup: fix docstring formatting...
r44226 """create a file containing the unfinalized state for
pretxnchangegroup"""
changelog-delay: adds some check around delaying and diverting write...
r51995 assert not self._inner.is_open
revlogv2: track pending write in the docket and expose it to hooks...
r48015 if self._docket:
changelog-delay: move the delay/divert logic inside the (inner) revlog...
r51999 any_pending = self._docket.write(tr, pending=True)
self._v2_delayed = False
else:
new_index, any_pending = self._inner.write_pending()
if new_index is not None:
self._indexfile = new_index
tr.registertmp(new_index)
return any_pending
Matt Mackall
Introduce HG_PREPEND to solve pretxn races...
r7787
revlog: improve the robustness of the splitting process...
r51242 def _enforceinlinesize(self, tr, side_write=True):
changelog-delay: move "delayed" check to a more official API...
r51997 if not self.is_delaying:
revlog: improve the robustness of the splitting process...
r51242 revlog.revlog._enforceinlinesize(self, tr, side_write=side_write)
Matt Mackall
restructure changelog file appending...
r4261
Joerg Sonnenberger
changelog: rename parameters to reflect semantics...
r47376 def read(self, nodeorrev):
Gregory Szorc
changelog: add class to represent parsed changelog revisions...
r28487 """Obtain data from a parsed changelog revision.
Returns a 6-tuple of:
Benoit Boissinot
[extendedchangelog] add extra metadata in the changelog entry...
r3233
Gregory Szorc
changelog: add class to represent parsed changelog revisions...
r28487 - manifest node in binary
- author/user as a localstr
- date as a 2-tuple of (time, timezone)
- list of files
- commit message as a localstr
- dict of extra metadata
Unless you need to access all fields, consider calling
``changelogrevision`` instead, as it is faster for partial object
access.
Benoit Boissinot
document changelog format
r3077 """
revlog: no longer return sidedata from `_revisiondata`...
r48177 d = self._revisiondata(nodeorrev)
revlog: use `self.sidedata` directly to construct changelogrevision...
r48175 sidedata = self.sidedata(nodeorrev)
copy_sd = self._copiesstorage == b'changeset-sidedata'
c = changelogrevision(self, d, sidedata, copy_sd)
Augie Fackler
formatting: blacken the codebase...
r43346 return (c.manifest, c.user, c.date, c.files, c.description, c.extra)
Benoit Boissinot
[extendedchangelog] add extra metadata in the changelog entry...
r3233
Gregory Szorc
changelog: add class to represent parsed changelog revisions...
r28487 def changelogrevision(self, nodeorrev):
"""Obtain a ``changelogrevision`` for a node or revision."""
revlog: no longer return sidedata from `_revisiondata`...
r48177 text = self._revisiondata(nodeorrev)
revlog: use `self.sidedata` directly to construct changelogrevision...
r48175 sidedata = self.sidedata(nodeorrev)
sidedatacopies: only read from copies when in this mode...
r43504 return changelogrevision(
Joerg Sonnenberger
node: introduce nodeconstants class...
r47538 self, text, sidedata, self._copiesstorage == b'changeset-sidedata'
sidedatacopies: only read from copies when in this mode...
r43504 )
mpm@selenic.com
Break apart hg.py...
r1089
Joerg Sonnenberger
changelog: rename parameters to reflect semantics...
r47376 def readfiles(self, nodeorrev):
Laurent Charignon
changelog: add a new method to get files modified by a changeset...
r27439 """
short version of read that only returns the files modified by the cset
"""
Joerg Sonnenberger
changelog: rename parameters to reflect semantics...
r47376 text = self.revision(nodeorrev)
Laurent Charignon
changelog: add a new method to get files modified by a changeset...
r27439 if not text:
return []
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 last = text.index(b"\n\n")
l = text[:last].split(b'\n')
Laurent Charignon
changelog: add a new method to get files modified by a changeset...
r27439 return l[3:]
Augie Fackler
formatting: blacken the codebase...
r43346 def add(
self,
manifest,
files,
desc,
transaction,
p1,
p2,
user,
date=None,
extra=None,
):
Martin Geisler
changelog: convert user and desc from local encoding early...
r14379 # Convert to UTF-8 encoded bytestrings as the very first
# thing: calling any method on a localstr object will turn it
# into a str object and the cached UTF-8 string is thus lost.
user, desc = encoding.fromlocal(user), encoding.fromlocal(desc)
Benoit Boissinot
forbid username with '\n' at the changelog level...
r7035 user = user.strip()
Martin Geisler
changelog: refuse to add revisions with empty usernames...
r8424 # An empty username or a username with a "\n" will make the
# revision text contain two "\n\n" sequences -> corrupt
# repository since read cannot unpack the revision.
if not user:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.StorageError(_(b"empty username"))
if b"\n" in user:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.StorageError(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"username %r contains a newline") % pycompat.bytestr(user)
Augie Fackler
formatting: blacken the codebase...
r43346 )
Matt Mackall
commit: move description trimming into changelog
r8499
Pierre-Yves David
changelog: extract description cleaning logic in a dedicated function...
r17810 desc = stripdesc(desc)
Matt Mackall
commit: move description trimming into changelog
r8499
Bryan O'Sullivan
Validate user input of dates when adding a changelog entry.
r1195 if date:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 parseddate = b"%d %d" % dateutil.parsedate(date)
Bryan O'Sullivan
Validate user input of dates when adding a changelog entry.
r1195 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 parseddate = b"%d %d" % dateutil.makedate()
Wagner Bruna
branch: avoid using reserved tag names...
r10417 if extra:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 branch = extra.get(b"branch")
if branch in (b"default", b""):
del extra[b"branch"]
elif branch in (b".", b"null", b"tip"):
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.StorageError(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'the name \'%s\' is reserved') % branch
Augie Fackler
formatting: blacken the codebase...
r43346 )
commitctx: directly pass a ChangingFiles object to changelog.add...
r45884 sortedfiles = sorted(files.touched)
copies: add a HASCOPIESINFO flag to highlight rev with useful data...
r46263 flags = 0
sidedatacopies: write copies information in sidedata when applicable...
r43412 sidedata = None
commitctx: extract copy information encoding into extra into commit.py...
r45809 if self._copiesstorage == b'changeset-sidedata':
changing-files: add a shorthand property to check for copy relevant info...
r46320 if files.has_copies_info:
copies: add a HASCOPIESINFO flag to highlight rev with useful data...
r46263 flags |= flagutil.REVIDX_HASCOPIESINFO
sidedata: rename `encode_copies_sidedata` to `encode_files_sidedata`...
r46143 sidedata = metadata.encode_files_sidedata(files)
Martin von Zweigbergk
copies: add config option for writing copy metadata to file and/or changset...
r42317
Benoit Boissinot
[extendedchangelog] add extra metadata in the changelog entry...
r3233 if extra:
Martin Geisler
changelog: turn {de,en}code_extra methods into functions...
r8443 extra = encodeextra(extra)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 parseddate = b"%s %s" % (parseddate, extra)
l = [hex(manifest), user, parseddate] + sortedfiles + [b"", desc]
text = b"\n".join(l)
Joerg Sonnenberger
revlog: change addrevision to return the new revision, not node...
r47258 rev = self.addrevision(
copies: return None instead of ChangingFiles when relevant...
r46264 text, transaction, len(self), p1, p2, sidedata=sidedata, flags=flags
sidedatacopies: write copies information in sidedata when applicable...
r43412 )
Joerg Sonnenberger
revlog: change addrevision to return the new revision, not node...
r47258 return self.node(rev)
Pierre-Yves David
changelog: add a `branch` method, bypassing changectx...
r18306
Brodie Rao
branchmap: cache open/closed branch head information...
r20185 def branchinfo(self, rev):
"""return the branch name and open/close state of a revision
Pierre-Yves David
changelog: add a `branch` method, bypassing changectx...
r18306
Mads Kiilerich
changelog: please check-code and remove tabs...
r18308 This function exists because creating a changectx object
just to access this is costly."""
Joerg Sonnenberger
changelog: move branchinfo to changelogrevision...
r47082 return self.changelogrevision(rev).branchinfo
Boris Feld
changelog: keep track of duplicated node in the transaction adding them...
r39923
Joerg Sonnenberger
revlog: change addgroup callbacks to take revision numbers...
r47259 def _nodeduplicatecallback(self, transaction, rev):
Boris Feld
changelog: keep track of duplicated node in the transaction adding them...
r39923 # keep track of revisions that got "re-added", eg: unbunde of know rev.
#
# We track them in a list to preserve their order from the source bundle
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 duplicates = transaction.changes.setdefault(b'revduplicates', [])
Joerg Sonnenberger
revlog: change addgroup callbacks to take revision numbers...
r47259 duplicates.append(rev)