filelog.py
239 lines
| 7.9 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, | ||
Gregory Szorc
|
r37459 | repository, | ||
Gregory Szorc
|
r25948 | revlog, | ||
) | ||||
Gregory Szorc
|
r37828 | from .utils import ( | ||
interfaceutil, | ||||
Gregory Szorc
|
r39914 | storageutil, | ||
Gregory Szorc
|
r37828 | ) | ||
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): | ||
Gregory Szorc
|
r37515 | self._revlog = revlog.revlog(opener, | ||
'/'.join(('data', path + '.i')), | ||||
censorable=True) | ||||
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): | ||||
Gregory Szorc
|
r40038 | 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) | ||||
Gregory Szorc
|
r39898 | def emitrevisions(self, nodes, nodesorder=None, | ||
revisiondata=False, assumehaveparentrevisions=False, | ||||
deltaprevious=False): | ||||
return self._revlog.emitrevisions( | ||||
nodes, nodesorder=nodesorder, revisiondata=revisiondata, | ||||
assumehaveparentrevisions=assumehaveparentrevisions, | ||||
deltaprevious=deltaprevious) | ||||
Gregory Szorc
|
r37515 | 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
|
r40425 | def addgroup(self, deltas, linkmapper, transaction, addrevisioncb=None, | ||
maybemissingparents=False): | ||||
if maybemissingparents: | ||||
raise error.Abort(_('revlog storage does not support missing ' | ||||
'parents write mode')) | ||||
Gregory Szorc
|
r37515 | return self._revlog.addgroup(deltas, linkmapper, transaction, | ||
Gregory Szorc
|
r40425 | addrevisioncb=addrevisioncb) | ||
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): | ||||
if meta or text.startswith('\1\n'): | ||||
Gregory Szorc
|
r39914 | text = storageutil.packmeta(meta, text) | ||
mpm@selenic.com
|
r1089 | return self.addrevision(text, transaction, link, p1, p2) | ||
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) | ||||
Gregory Szorc
|
r39905 | def storageinfo(self, exclusivefiles=False, sharedfiles=False, | ||
revisionscount=False, trackedsize=False, | ||||
storedsize=False): | ||||
return self._revlog.storageinfo( | ||||
exclusivefiles=exclusivefiles, sharedfiles=sharedfiles, | ||||
revisionscount=revisionscount, trackedsize=trackedsize, | ||||
storedsize=storedsize) | ||||
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): | ||||
raise error.ProgrammingError('expected filelog to clone()') | ||||
return self._revlog.clone(tr, destrevlog._revlog, **kwargs) | ||||
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 | ||||