filelog.py
293 lines
| 8.4 KiB
| text/x-python
|
PythonLexer
/ mercurial / filelog.py
mpm@selenic.com
|
r1089 | # filelog.py - file history class for mercurial | ||
# | ||||
Thomas Arendsen Hein
|
r4635 | # Copyright 2005-2007 Matt Mackall <mpm@selenic.com> | ||
mpm@selenic.com
|
r1089 | # | ||
Martin Geisler
|
r8225 | # This software may be used and distributed according to the terms of the | ||
Matt Mackall
|
r10263 | # GNU General Public License version 2 or any later version. | ||
mpm@selenic.com
|
r1089 | |||
Gregory Szorc
|
r25948 | from __future__ import absolute_import | ||
Gregory Szorc
|
r40425 | from .i18n import _ | ||
Gregory Szorc
|
r40423 | from .node import ( | ||
nullid, | ||||
nullrev, | ||||
) | ||||
Gregory Szorc
|
r25948 | from . import ( | ||
Gregory Szorc
|
r37515 | error, | ||
Pulkit Goyal
|
r43078 | revlog, | ||
) | ||||
from .interfaces import ( | ||||
Gregory Szorc
|
r37459 | repository, | ||
Pulkit Goyal
|
r43079 | util as interfaceutil, | ||
Gregory Szorc
|
r25948 | ) | ||
Augie Fackler
|
r43346 | from .utils import storageutil | ||
mpm@selenic.com
|
r1089 | |||
Gregory Szorc
|
r37828 | @interfaceutil.implementer(repository.ifilestorage) | ||
Gregory Szorc
|
r37515 | class filelog(object): | ||
Matt Mackall
|
r4258 | def __init__(self, opener, path): | ||
Augie Fackler
|
r43346 | self._revlog = revlog.revlog( | ||
Augie Fackler
|
r43347 | opener, b'/'.join((b'data', path + b'.i')), censorable=True | ||
Augie Fackler
|
r43346 | ) | ||
Gregory Szorc
|
r39819 | # Full name of the user visible file, relative to the repository root. | ||
# Used by LFS. | ||||
Gregory Szorc
|
r39892 | self._revlog.filename = path | ||
Gregory Szorc
|
r37515 | |||
def __len__(self): | ||||
return len(self._revlog) | ||||
def __iter__(self): | ||||
return self._revlog.__iter__() | ||||
Gregory Szorc
|
r40423 | def hasnode(self, node): | ||
if node in (nullid, nullrev): | ||||
return False | ||||
try: | ||||
self._revlog.rev(node) | ||||
return True | ||||
except (TypeError, ValueError, IndexError, error.LookupError): | ||||
return False | ||||
Gregory Szorc
|
r37515 | def revs(self, start=0, stop=None): | ||
return self._revlog.revs(start=start, stop=stop) | ||||
def parents(self, node): | ||||
return self._revlog.parents(node) | ||||
def parentrevs(self, rev): | ||||
return self._revlog.parentrevs(rev) | ||||
def rev(self, node): | ||||
return self._revlog.rev(node) | ||||
def node(self, rev): | ||||
return self._revlog.node(rev) | ||||
def lookup(self, node): | ||||
Augie Fackler
|
r43346 | return storageutil.fileidlookup( | ||
self._revlog, node, self._revlog.indexfile | ||||
) | ||||
Gregory Szorc
|
r37515 | |||
def linkrev(self, rev): | ||||
return self._revlog.linkrev(rev) | ||||
def commonancestorsheads(self, node1, node2): | ||||
return self._revlog.commonancestorsheads(node1, node2) | ||||
Gregory Szorc
|
r39819 | # Used by dagop.blockdescendants(). | ||
Gregory Szorc
|
r37515 | def descendants(self, revs): | ||
return self._revlog.descendants(revs) | ||||
def heads(self, start=None, stop=None): | ||||
return self._revlog.heads(start, stop) | ||||
Gregory Szorc
|
r39819 | # Used by hgweb, children extension. | ||
Gregory Szorc
|
r37515 | def children(self, node): | ||
return self._revlog.children(node) | ||||
def iscensored(self, rev): | ||||
return self._revlog.iscensored(rev) | ||||
def revision(self, node, _df=None, raw=False): | ||||
return self._revlog.revision(node, _df=_df, raw=raw) | ||||
r42946 | def rawdata(self, node, _df=None): | |||
return self._revlog.rawdata(node, _df=_df) | ||||
Augie Fackler
|
r43346 | def emitrevisions( | ||
self, | ||||
nodes, | ||||
nodesorder=None, | ||||
revisiondata=False, | ||||
assumehaveparentrevisions=False, | ||||
deltamode=repository.CG_DELTAMODE_STD, | ||||
): | ||||
Gregory Szorc
|
r39898 | return self._revlog.emitrevisions( | ||
Augie Fackler
|
r43346 | nodes, | ||
nodesorder=nodesorder, | ||||
revisiondata=revisiondata, | ||||
Gregory Szorc
|
r39898 | assumehaveparentrevisions=assumehaveparentrevisions, | ||
Augie Fackler
|
r43346 | deltamode=deltamode, | ||
) | ||||
Gregory Szorc
|
r39898 | |||
Augie Fackler
|
r43346 | def addrevision( | ||
self, | ||||
revisiondata, | ||||
transaction, | ||||
linkrev, | ||||
p1, | ||||
p2, | ||||
node=None, | ||||
flags=revlog.REVIDX_DEFAULT_FLAGS, | ||||
cachedelta=None, | ||||
): | ||||
return self._revlog.addrevision( | ||||
revisiondata, | ||||
transaction, | ||||
linkrev, | ||||
p1, | ||||
p2, | ||||
node=node, | ||||
flags=flags, | ||||
cachedelta=cachedelta, | ||||
) | ||||
Gregory Szorc
|
r37515 | |||
Augie Fackler
|
r43346 | def addgroup( | ||
self, | ||||
deltas, | ||||
linkmapper, | ||||
transaction, | ||||
addrevisioncb=None, | ||||
Joerg Sonnenberger
|
r46373 | duplicaterevisioncb=None, | ||
Augie Fackler
|
r43346 | maybemissingparents=False, | ||
): | ||||
Gregory Szorc
|
r40425 | if maybemissingparents: | ||
Augie Fackler
|
r43346 | raise error.Abort( | ||
_( | ||||
Augie Fackler
|
r43347 | b'revlog storage does not support missing ' | ||
b'parents write mode' | ||||
Augie Fackler
|
r43346 | ) | ||
) | ||||
Gregory Szorc
|
r40425 | |||
Augie Fackler
|
r43346 | return self._revlog.addgroup( | ||
Joerg Sonnenberger
|
r46373 | deltas, | ||
linkmapper, | ||||
transaction, | ||||
addrevisioncb=addrevisioncb, | ||||
duplicaterevisioncb=duplicaterevisioncb, | ||||
Augie Fackler
|
r43346 | ) | ||
Gregory Szorc
|
r37515 | |||
def getstrippoint(self, minlink): | ||||
return self._revlog.getstrippoint(minlink) | ||||
def strip(self, minlink, transaction): | ||||
return self._revlog.strip(minlink, transaction) | ||||
Gregory Szorc
|
r39814 | def censorrevision(self, tr, node, tombstone=b''): | ||
Gregory Szorc
|
r40092 | return self._revlog.censorrevision(tr, node, tombstone=tombstone) | ||
Gregory Szorc
|
r39814 | |||
Gregory Szorc
|
r37515 | def files(self): | ||
return self._revlog.files() | ||||
mpm@selenic.com
|
r1089 | def read(self, node): | ||
Gregory Szorc
|
r39916 | return storageutil.filtermetadata(self.revision(node)) | ||
mpm@selenic.com
|
r1089 | |||
def add(self, text, meta, transaction, link, p1=None, p2=None): | ||||
Augie Fackler
|
r43347 | if meta or text.startswith(b'\1\n'): | ||
Gregory Szorc
|
r39914 | text = storageutil.packmeta(meta, text) | ||
Joerg Sonnenberger
|
r47258 | rev = self.addrevision(text, transaction, link, p1, p2) | ||
return self.node(rev) | ||||
mpm@selenic.com
|
r1089 | |||
mpm@selenic.com
|
r1116 | def renamed(self, node): | ||
Gregory Szorc
|
r40041 | return storageutil.filerevisioncopied(self, node) | ||
mpm@selenic.com
|
r1116 | |||
Matt Mackall
|
r2898 | def size(self, rev): | ||
"""return the size of a given revision""" | ||||
# for revisions with renames, we have to go the slow way | ||||
node = self.node(rev) | ||||
if self.renamed(node): | ||||
return len(self.read(node)) | ||||
Mike Edgar
|
r24118 | if self.iscensored(rev): | ||
Mike Edgar
|
r22597 | return 0 | ||
Matt Mackall
|
r2898 | |||
Nicolas Dumazet
|
r11540 | # XXX if self.read(node).startswith("\1\n"), this returns (size+4) | ||
Gregory Szorc
|
r37515 | return self._revlog.size(rev) | ||
Matt Mackall
|
r2898 | |||
Matt Mackall
|
r2887 | def cmp(self, node, text): | ||
Nicolas Dumazet
|
r11539 | """compare text with a given file revision | ||
returns True if text is different than what is stored. | ||||
""" | ||||
Gregory Szorc
|
r40043 | return not storageutil.filedataequivalent(self, node, text) | ||
Gregory Szorc
|
r37515 | |||
Gregory Szorc
|
r39878 | def verifyintegrity(self, state): | ||
return self._revlog.verifyintegrity(state) | ||||
Augie Fackler
|
r43346 | def storageinfo( | ||
self, | ||||
exclusivefiles=False, | ||||
sharedfiles=False, | ||||
revisionscount=False, | ||||
trackedsize=False, | ||||
storedsize=False, | ||||
): | ||||
Gregory Szorc
|
r39905 | return self._revlog.storageinfo( | ||
Augie Fackler
|
r43346 | exclusivefiles=exclusivefiles, | ||
sharedfiles=sharedfiles, | ||||
revisionscount=revisionscount, | ||||
trackedsize=trackedsize, | ||||
storedsize=storedsize, | ||||
) | ||||
Gregory Szorc
|
r39905 | |||
Gregory Szorc
|
r39819 | # TODO these aren't part of the interface and aren't internal methods. | ||
# Callers should be fixed to not use them. | ||||
# Used by bundlefilelog, unionfilelog. | ||||
Gregory Szorc
|
r37515 | @property | ||
def indexfile(self): | ||||
return self._revlog.indexfile | ||||
@indexfile.setter | ||||
def indexfile(self, value): | ||||
self._revlog.indexfile = value | ||||
Gregory Szorc
|
r39819 | # Used by repo upgrade. | ||
Gregory Szorc
|
r37515 | def clone(self, tr, destrevlog, **kwargs): | ||
if not isinstance(destrevlog, filelog): | ||||
Augie Fackler
|
r43347 | raise error.ProgrammingError(b'expected filelog to clone()') | ||
Gregory Szorc
|
r37515 | |||
return self._revlog.clone(tr, destrevlog._revlog, **kwargs) | ||||
Augie Fackler
|
r43346 | |||
Gregory Szorc
|
r39801 | class narrowfilelog(filelog): | ||
"""Filelog variation to be used with narrow stores.""" | ||||
def __init__(self, opener, path, narrowmatch): | ||||
super(narrowfilelog, self).__init__(opener, path) | ||||
self._narrowmatch = narrowmatch | ||||
def renamed(self, node): | ||||
res = super(narrowfilelog, self).renamed(node) | ||||
# Renames that come from outside the narrowspec are problematic | ||||
# because we may lack the base text for the rename. This can result | ||||
# in code attempting to walk the ancestry or compute a diff | ||||
# encountering a missing revision. We address this by silently | ||||
# removing rename metadata if the source file is outside the | ||||
# narrow spec. | ||||
# | ||||
# A better solution would be to see if the base revision is available, | ||||
# rather than assuming it isn't. | ||||
# | ||||
# An even better solution would be to teach all consumers of rename | ||||
# metadata that the base revision may not be available. | ||||
# | ||||
# TODO consider better ways of doing this. | ||||
if res and not self._narrowmatch(res[0]): | ||||
return None | ||||
return res | ||||
def size(self, rev): | ||||
# Because we have a custom renamed() that may lie, we need to call | ||||
# the base renamed() to report accurate results. | ||||
node = self.node(rev) | ||||
if super(narrowfilelog, self).renamed(node): | ||||
return len(self.read(node)) | ||||
else: | ||||
return super(narrowfilelog, self).size(rev) | ||||
def cmp(self, node, text): | ||||
different = super(narrowfilelog, self).cmp(node, text) | ||||
# Because renamed() may lie, we may get false positives for | ||||
# different content. Check for this by comparing against the original | ||||
# renamed() implementation. | ||||
if different: | ||||
if super(narrowfilelog, self).renamed(node): | ||||
t2 = self.read(node) | ||||
return t2 != text | ||||
return different | ||||