##// END OF EJS Templates
phabricator: rework phabread to reduce memory usage and round-trips...
phabricator: rework phabread to reduce memory usage and round-trips This patch reworked phabread a bit so it fetches the lightweight "Differential Revision" metadata for a stack first. Then read other data. This allows the code to: a) send 1 request to get all `hg:meta` data instead of N requests b) patches are read in desired order, no need to buffer the output "b)" reduces the memory usage from O(N^2) to O(N) since we no longer keep old patch contents in memory. The above `N` means the number of patches in the stack.

File last commit:

r33172:3b85c474 default
r33267:dba9f886 default
Show More
manifest.py
1640 lines | 53.4 KiB | text/x-python | PythonLexer
mpm@selenic.com
Break apart hg.py...
r1089 # manifest.py - manifest revision class for mercurial
#
Thomas Arendsen Hein
Updated copyright notices and add "and others" to "hg version"
r4635 # Copyright 2005-2007 Matt Mackall <mpm@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
manifest: use absolute_import
r27502 from __future__ import absolute_import
import heapq
Augie Fackler
manifest: use itertools.chain() instead of + for Python 3 compat...
r32536 import itertools
Martin von Zweigbergk
manifestv2: add support for writing new manifest format...
r24573 import os
Gregory Szorc
manifest: use absolute_import
r27502 import struct
from .i18n import _
Augie Fackler
manifest: use node.hex instead of .encode('hex')...
r31530 from .node import (
bin,
hex,
)
Gregory Szorc
manifest: use absolute_import
r27502 from . import (
error,
mdiff,
Yuya Nishihara
parsers: switch to policy importer...
r32372 policy,
Gregory Szorc
manifest: use absolute_import
r27502 revlog,
util,
)
mpm@selenic.com
Break apart hg.py...
r1089
Yuya Nishihara
parsers: switch to policy importer...
r32372 parsers = policy.importmod(r'parsers')
Drew Gottlieb
manifest: add dirs() to manifestdict...
r24322 propertycache = util.propertycache
Augie Fackler
manifest: split manifestdict into high-level and low-level logic...
r24225
Martin von Zweigbergk
manifestv2: add support for reading new manifest format...
r24572 def _parsev1(data):
Martin von Zweigbergk
manifest: extract method for parsing manifest...
r24524 # This method does a little bit of excessive-looking
# precondition checking. This is so that the behavior of this
# class exactly matches its C counterpart to try and help
# prevent surprise breakage for anyone that develops against
# the pure version.
Augie Fackler
manifest: fix some pure-Python parser bits to work on Python 3
r32535 if data and data[-1:] != '\n':
Martin von Zweigbergk
manifest: extract method for parsing manifest...
r24524 raise ValueError('Manifest did not end in a newline.')
prev = None
for l in data.splitlines():
if prev is not None and prev > l:
raise ValueError('Manifest lines not in sorted order.')
prev = l
f, n = l.split('\0')
if len(n) > 40:
Augie Fackler
manifest: now that node.bin is available, use it directly...
r31366 yield f, bin(n[:40]), n[40:]
Martin von Zweigbergk
manifest: extract method for parsing manifest...
r24524 else:
Augie Fackler
manifest: now that node.bin is available, use it directly...
r31366 yield f, bin(n), ''
Martin von Zweigbergk
manifest: extract method for parsing manifest...
r24524
Martin von Zweigbergk
manifestv2: add support for reading new manifest format...
r24572 def _parsev2(data):
metadataend = data.find('\n')
# Just ignore metadata for now
pos = metadataend + 1
prevf = ''
while pos < len(data):
end = data.find('\n', pos + 1) # +1 to skip stem length byte
if end == -1:
raise ValueError('Manifest ended with incomplete file entry.')
Augie Fackler
manifest: fix some pure-Python parser bits to work on Python 3
r32535 stemlen = ord(data[pos:pos + 1])
Martin von Zweigbergk
manifestv2: add support for reading new manifest format...
r24572 items = data[pos + 1:end].split('\0')
f = prevf[:stemlen] + items[0]
if prevf > f:
raise ValueError('Manifest entries not in sorted order.')
fl = items[1]
# Just ignore metadata (items[2:] for now)
n = data[end + 1:end + 21]
yield f, n, fl
pos = end + 22
prevf = f
def _parse(data):
"""Generates (path, node, flags) tuples from a manifest text"""
if data.startswith('\0'):
return iter(_parsev2(data))
else:
return iter(_parsev1(data))
Martin von Zweigbergk
manifestv2: add support for writing new manifest format...
r24573 def _text(it, usemanifestv2):
Martin von Zweigbergk
manifest: extract method for creating manifest text...
r24525 """Given an iterator over (path, node, flags) tuples, returns a manifest
text"""
Martin von Zweigbergk
manifestv2: add support for writing new manifest format...
r24573 if usemanifestv2:
return _textv2(it)
else:
return _textv1(it)
def _textv1(it):
Martin von Zweigbergk
manifest: extract method for creating manifest text...
r24525 files = []
lines = []
_hex = revlog.hex
for f, n, fl in it:
files.append(f)
# if this is changed to support newlines in filenames,
# be sure to check the templates/ dir again (especially *-raw.tmpl)
lines.append("%s\0%s%s\n" % (f, _hex(n), fl))
_checkforbidden(files)
return ''.join(lines)
Martin von Zweigbergk
manifestv2: add support for writing new manifest format...
r24573 def _textv2(it):
files = []
lines = ['\0\n']
prevf = ''
for f, n, fl in it:
files.append(f)
stem = os.path.commonprefix([prevf, f])
stemlen = min(len(stem), 255)
lines.append("%c%s\0%s\n%s\n" % (stemlen, f[stemlen:], fl, n))
prevf = f
_checkforbidden(files)
return ''.join(lines)
Maciej Fijalkowski
lazymanifest: write a more efficient, pypy friendly version of lazymanifest
r30042 class lazymanifestiter(object):
def __init__(self, lm):
self.pos = 0
self.lm = lm
Augie Fackler
manifest: split manifestdict into high-level and low-level logic...
r24225
Maciej Fijalkowski
lazymanifest: write a more efficient, pypy friendly version of lazymanifest
r30042 def __iter__(self):
return self
Augie Fackler
manifest: move parsing functions up in file...
r24223
Maciej Fijalkowski
lazymanifest: write a more efficient, pypy friendly version of lazymanifest
r30042 def next(self):
try:
data, pos = self.lm._get(self.pos)
except IndexError:
raise StopIteration
if pos == -1:
self.pos += 1
return data[0]
self.pos += 1
zeropos = data.find('\x00', pos)
return data[pos:zeropos]
Augie Fackler
manifest: do parsing inside manifestdict contstructor...
r24224
Augie Fackler
manifest: add __next__ methods for Python 3...
r31364 __next__ = next
Maciej Fijalkowski
lazymanifest: write a more efficient, pypy friendly version of lazymanifest
r30042 class lazymanifestiterentries(object):
def __init__(self, lm):
self.lm = lm
self.pos = 0
Augie Fackler
manifest: split manifestdict into high-level and low-level logic...
r24225
def __iter__(self):
Maciej Fijalkowski
lazymanifest: write a more efficient, pypy friendly version of lazymanifest
r30042 return self
def next(self):
try:
data, pos = self.lm._get(self.pos)
except IndexError:
raise StopIteration
if pos == -1:
self.pos += 1
return data
zeropos = data.find('\x00', pos)
hashval = unhexlify(data, self.lm.extrainfo[self.pos],
zeropos + 1, 40)
flags = self.lm._getflags(data, self.pos, zeropos)
self.pos += 1
return (data[pos:zeropos], hashval, flags)
Augie Fackler
manifest: add __next__ methods for Python 3...
r31364 __next__ = next
Maciej Fijalkowski
lazymanifest: write a more efficient, pypy friendly version of lazymanifest
r30042 def unhexlify(data, extra, pos, length):
Augie Fackler
manifest: use node.bin instead of .decode('hex')...
r31365 s = bin(data[pos:pos + length])
Maciej Fijalkowski
lazymanifest: write a more efficient, pypy friendly version of lazymanifest
r30042 if extra:
s += chr(extra & 0xff)
return s
def _cmp(a, b):
return (a > b) - (a < b)
class _lazymanifest(object):
def __init__(self, data, positions=None, extrainfo=None, extradata=None):
if positions is None:
self.positions = self.findlines(data)
self.extrainfo = [0] * len(self.positions)
self.data = data
self.extradata = []
else:
self.positions = positions[:]
self.extrainfo = extrainfo[:]
self.extradata = extradata[:]
self.data = data
def findlines(self, data):
if not data:
return []
pos = data.find("\n")
Augie Fackler
manifest: unbreak pure-python manifest parsing on Python 3
r31352 if pos == -1 or data[-1:] != '\n':
Maciej Fijalkowski
lazymanifest: write a more efficient, pypy friendly version of lazymanifest
r30042 raise ValueError("Manifest did not end in a newline.")
positions = [0]
prev = data[:data.find('\x00')]
while pos < len(data) - 1 and pos != -1:
positions.append(pos + 1)
nexts = data[pos + 1:data.find('\x00', pos + 1)]
if nexts < prev:
raise ValueError("Manifest lines not in sorted order.")
prev = nexts
pos = data.find("\n", pos + 1)
return positions
def _get(self, index):
# get the position encoded in pos:
# positive number is an index in 'data'
# negative number is in extrapieces
pos = self.positions[index]
if pos >= 0:
return self.data, pos
return self.extradata[-pos - 1], -1
def _getkey(self, pos):
if pos >= 0:
return self.data[pos:self.data.find('\x00', pos + 1)]
return self.extradata[-pos - 1][0]
def bsearch(self, key):
first = 0
last = len(self.positions) - 1
while first <= last:
midpoint = (first + last)//2
nextpos = self.positions[midpoint]
candidate = self._getkey(nextpos)
r = _cmp(key, candidate)
if r == 0:
return midpoint
else:
if r < 0:
last = midpoint - 1
else:
first = midpoint + 1
return -1
Augie Fackler
manifest: split manifestdict into high-level and low-level logic...
r24225
Maciej Fijalkowski
lazymanifest: write a more efficient, pypy friendly version of lazymanifest
r30042 def bsearch2(self, key):
# same as the above, but will always return the position
# done for performance reasons
first = 0
last = len(self.positions) - 1
while first <= last:
midpoint = (first + last)//2
nextpos = self.positions[midpoint]
candidate = self._getkey(nextpos)
r = _cmp(key, candidate)
if r == 0:
return (midpoint, True)
else:
if r < 0:
last = midpoint - 1
else:
first = midpoint + 1
return (first, False)
def __contains__(self, key):
return self.bsearch(key) != -1
def _getflags(self, data, needle, pos):
start = pos + 41
end = data.find("\n", start)
if end == -1:
end = len(data) - 1
if start == end:
return ''
return self.data[start:end]
Martin von Zweigbergk
lazymanifest: fix pure hg iterkeys()...
r24297
Maciej Fijalkowski
lazymanifest: write a more efficient, pypy friendly version of lazymanifest
r30042 def __getitem__(self, key):
Augie Fackler
manifest: ensure paths are bytes (not str) in pure parser
r31367 if not isinstance(key, bytes):
raise TypeError("getitem: manifest keys must be a bytes.")
Maciej Fijalkowski
lazymanifest: write a more efficient, pypy friendly version of lazymanifest
r30042 needle = self.bsearch(key)
if needle == -1:
raise KeyError
data, pos = self._get(needle)
if pos == -1:
return (data[1], data[2])
zeropos = data.find('\x00', pos)
assert 0 <= needle <= len(self.positions)
assert len(self.extrainfo) == len(self.positions)
hashval = unhexlify(data, self.extrainfo[needle], zeropos + 1, 40)
flags = self._getflags(data, needle, zeropos)
return (hashval, flags)
def __delitem__(self, key):
needle, found = self.bsearch2(key)
if not found:
raise KeyError
cur = self.positions[needle]
self.positions = self.positions[:needle] + self.positions[needle + 1:]
self.extrainfo = self.extrainfo[:needle] + self.extrainfo[needle + 1:]
if cur >= 0:
self.data = self.data[:cur] + '\x00' + self.data[cur + 1:]
def __setitem__(self, key, value):
Augie Fackler
manifest: refer to bytestrings as bytes, not str...
r31531 if not isinstance(key, bytes):
raise TypeError("setitem: manifest keys must be a byte string.")
Maciej Fijalkowski
lazymanifest: write a more efficient, pypy friendly version of lazymanifest
r30042 if not isinstance(value, tuple) or len(value) != 2:
raise TypeError("Manifest values must be a tuple of (node, flags).")
hashval = value[0]
Augie Fackler
manifest: refer to bytestrings as bytes, not str...
r31531 if not isinstance(hashval, bytes) or not 20 <= len(hashval) <= 22:
raise TypeError("node must be a 20-byte byte string")
Maciej Fijalkowski
lazymanifest: write a more efficient, pypy friendly version of lazymanifest
r30042 flags = value[1]
if len(hashval) == 22:
hashval = hashval[:-1]
Augie Fackler
manifest: refer to bytestrings as bytes, not str...
r31531 if not isinstance(flags, bytes) or len(flags) > 1:
Maciej Fijalkowski
lazymanifest: write a more efficient, pypy friendly version of lazymanifest
r30042 raise TypeError("flags must a 0 or 1 byte string, got %r", flags)
needle, found = self.bsearch2(key)
if found:
# put the item
pos = self.positions[needle]
if pos < 0:
self.extradata[-pos - 1] = (key, hashval, value[1])
else:
# just don't bother
self.extradata.append((key, hashval, value[1]))
self.positions[needle] = -len(self.extradata)
else:
# not found, put it in with extra positions
self.extradata.append((key, hashval, value[1]))
self.positions = (self.positions[:needle] + [-len(self.extradata)]
+ self.positions[needle:])
self.extrainfo = (self.extrainfo[:needle] + [0] +
self.extrainfo[needle:])
Martin von Zweigbergk
lazymanifest: make __iter__ generate filenames, not 3-tuples...
r24298
Matt Mackall
Add manifestflags class
r2831 def copy(self):
Maciej Fijalkowski
lazymanifest: write a more efficient, pypy friendly version of lazymanifest
r30042 # XXX call _compact like in C?
return _lazymanifest(self.data, self.positions, self.extrainfo,
self.extradata)
def _compact(self):
# hopefully not called TOO often
if len(self.extradata) == 0:
return
l = []
last_cut = 0
i = 0
offset = 0
self.extrainfo = [0] * len(self.positions)
while i < len(self.positions):
if self.positions[i] >= 0:
cur = self.positions[i]
last_cut = cur
while True:
self.positions[i] = offset
i += 1
if i == len(self.positions) or self.positions[i] < 0:
break
offset += self.positions[i] - cur
cur = self.positions[i]
end_cut = self.data.find('\n', cur)
if end_cut != -1:
end_cut += 1
offset += end_cut - cur
l.append(self.data[last_cut:end_cut])
else:
while i < len(self.positions) and self.positions[i] < 0:
cur = self.positions[i]
t = self.extradata[-cur - 1]
l.append(self._pack(t))
self.positions[i] = offset
if len(t[1]) > 20:
self.extrainfo[i] = ord(t[1][21])
offset += len(l[-1])
i += 1
self.data = ''.join(l)
self.extradata = []
def _pack(self, d):
Augie Fackler
manifest: use node.hex instead of .encode('hex')...
r31530 return d[0] + '\x00' + hex(d[1][:20]) + d[2] + '\n'
Maciej Fijalkowski
lazymanifest: write a more efficient, pypy friendly version of lazymanifest
r30042
def text(self):
self._compact()
return self.data
Augie Fackler
manifest: split manifestdict into high-level and low-level logic...
r24225
def diff(self, m2, clean=False):
'''Finds changes between the current manifest and m2.'''
Maciej Fijalkowski
lazymanifest: write a more efficient, pypy friendly version of lazymanifest
r30042 # XXX think whether efficiency matters here
Augie Fackler
manifest: split manifestdict into high-level and low-level logic...
r24225 diff = {}
Maciej Fijalkowski
lazymanifest: write a more efficient, pypy friendly version of lazymanifest
r30042 for fn, e1, flags in self.iterentries():
Augie Fackler
manifest: split manifestdict into high-level and low-level logic...
r24225 if fn not in m2:
Maciej Fijalkowski
lazymanifest: write a more efficient, pypy friendly version of lazymanifest
r30042 diff[fn] = (e1, flags), (None, '')
Augie Fackler
manifest: split manifestdict into high-level and low-level logic...
r24225 else:
e2 = m2[fn]
Maciej Fijalkowski
lazymanifest: write a more efficient, pypy friendly version of lazymanifest
r30042 if (e1, flags) != e2:
diff[fn] = (e1, flags), e2
Augie Fackler
manifest: split manifestdict into high-level and low-level logic...
r24225 elif clean:
diff[fn] = None
Maciej Fijalkowski
lazymanifest: write a more efficient, pypy friendly version of lazymanifest
r30042 for fn, e2, flags in m2.iterentries():
Augie Fackler
manifest: split manifestdict into high-level and low-level logic...
r24225 if fn not in self:
Maciej Fijalkowski
lazymanifest: write a more efficient, pypy friendly version of lazymanifest
r30042 diff[fn] = (None, ''), (e2, flags)
Augie Fackler
manifest: split manifestdict into high-level and low-level logic...
r24225
return diff
Maciej Fijalkowski
lazymanifest: write a more efficient, pypy friendly version of lazymanifest
r30042 def iterentries(self):
return lazymanifestiterentries(self)
def iterkeys(self):
return lazymanifestiter(self)
def __iter__(self):
return lazymanifestiter(self)
def __len__(self):
return len(self.positions)
Augie Fackler
manifest: split manifestdict into high-level and low-level logic...
r24225 def filtercopy(self, filterfn):
Maciej Fijalkowski
lazymanifest: write a more efficient, pypy friendly version of lazymanifest
r30042 # XXX should be optimized
Augie Fackler
manifest: split manifestdict into high-level and low-level logic...
r24225 c = _lazymanifest('')
Martin von Zweigbergk
lazymanifest: make __iter__ generate filenames, not 3-tuples...
r24298 for f, n, fl in self.iterentries():
Augie Fackler
manifest: split manifestdict into high-level and low-level logic...
r24225 if filterfn(f):
c[f] = n, fl
return c
Augie Fackler
manifest: use custom C implementation of lazymanifest...
r24226 try:
_lazymanifest = parsers.lazymanifest
except AttributeError:
pass
Augie Fackler
manifest: split manifestdict into high-level and low-level logic...
r24225 class manifestdict(object):
def __init__(self, data=''):
Martin von Zweigbergk
manifestv2: add support for reading new manifest format...
r24572 if data.startswith('\0'):
#_lazymanifest can not parse v2
self._lm = _lazymanifest('')
for f, n, fl in _parsev2(data):
self._lm[f] = n, fl
else:
self._lm = _lazymanifest(data)
Augie Fackler
manifest: split manifestdict into high-level and low-level logic...
r24225
def __getitem__(self, key):
return self._lm[key][0]
Martin von Zweigbergk
manifest: don't let find() look inside manifestdict...
r24277 def find(self, key):
return self._lm[key]
Augie Fackler
manifest: split manifestdict into high-level and low-level logic...
r24225 def __len__(self):
return len(self._lm)
Durham Goode
manifest: add __nonzero__ method...
r30331 def __nonzero__(self):
# nonzero is covered by the __len__ function, but implementing it here
# makes it easier for extensions to override.
return len(self._lm) != 0
Gregory Szorc
py3: add __bool__ to every class defining __nonzero__...
r31476 __bool__ = __nonzero__
Augie Fackler
manifest: split manifestdict into high-level and low-level logic...
r24225 def __setitem__(self, key, node):
self._lm[key] = node, self.flags(key, '')
def __contains__(self, key):
return key in self._lm
def __delitem__(self, key):
del self._lm[key]
Martin von Zweigbergk
lazymanifest: add iterkeys() method...
r24295 def __iter__(self):
Martin von Zweigbergk
lazymanifest: make __iter__ generate filenames, not 3-tuples...
r24298 return self._lm.__iter__()
Augie Fackler
manifest: split manifestdict into high-level and low-level logic...
r24225
def iterkeys(self):
Martin von Zweigbergk
lazymanifest: add iterkeys() method...
r24295 return self._lm.iterkeys()
def keys(self):
return list(self.iterkeys())
Augie Fackler
manifest: split manifestdict into high-level and low-level logic...
r24225
Durham Goode
manifest: add match argument to diff and filesnotin...
r31255 def filesnotin(self, m2, match=None):
Martin von Zweigbergk
copies: move code into new manifestdict.filesnotin() method...
r24184 '''Set of files in this manifest that are not in the other'''
Durham Goode
manifest: add match argument to diff and filesnotin...
r31255 if match:
m1 = self.matches(match)
m2 = m2.matches(match)
return m1.filesnotin(m2)
Tony Tung
manifest: improve filesnotin performance by using lazymanifest diff...
r29056 diff = self.diff(m2)
files = set(filepath
for filepath, hashflags in diff.iteritems()
if hashflags[1][0] is None)
Martin von Zweigbergk
copies: move code into new manifestdict.filesnotin() method...
r24184 return files
Drew Gottlieb
manifest: add dirs() to manifestdict...
r24322 @propertycache
def _dirs(self):
Drew Gottlieb
util: move dirs() and finddirs() from scmutil to util...
r24635 return util.dirs(self)
Drew Gottlieb
manifest: add dirs() to manifestdict...
r24322
def dirs(self):
return self._dirs
Drew Gottlieb
manifest: add manifestdict.hasdir() method...
r24324 def hasdir(self, dir):
return dir in self._dirs
Martin von Zweigbergk
manifestdict: extract condition for _intersectfiles() and use for walk()...
r24685 def _filesfastpath(self, match):
'''Checks whether we can correctly and quickly iterate over matcher
files instead of over manifest files.'''
files = match.files()
return (len(files) < 100 and (match.isexact() or
Martin von Zweigbergk
manifest: use match.prefix() instead of 'not match.anypats()'...
r25276 (match.prefix() and all(fn in self for fn in files))))
Martin von Zweigbergk
manifestdict: extract condition for _intersectfiles() and use for walk()...
r24685
Drew Gottlieb
manifest: move changectx.walk() to manifests...
r24646 def walk(self, match):
'''Generates matching file names.
Equivalent to manifest.matches(match).iterkeys(), but without creating
an entirely new manifest.
It also reports nonexistent files by marking them bad with match.bad().
'''
Martin von Zweigbergk
manifest.walk: special-case match.always() for speed...
r24683 if match.always():
for f in iter(self):
yield f
return
Drew Gottlieb
manifest: move changectx.walk() to manifests...
r24646 fset = set(match.files())
# avoid the entire walk if we're only looking for specific files
Martin von Zweigbergk
manifestdict: extract condition for _intersectfiles() and use for walk()...
r24685 if self._filesfastpath(match):
Martin von Zweigbergk
manifest.walk: join nested if-conditions...
r24667 for fn in sorted(fset):
yield fn
Martin von Zweigbergk
manifest.walk: use return instead of StopIteration in generator...
r24682 return
Drew Gottlieb
manifest: move changectx.walk() to manifests...
r24646
for fn in self:
if fn in fset:
# specified pattern is the exact name
fset.remove(fn)
if match(fn):
yield fn
# for dirstate.walk, files=['.'] means "walk the whole tree".
# follow that here, too
fset.discard('.')
for fn in sorted(fset):
if not self.hasdir(fn):
match.bad(fn, None)
Martin von Zweigbergk
manifest: add matches() method...
r23305 def matches(self, match):
'''generate a new manifest filtered by the match argument'''
if match.always():
return self.copy()
Martin von Zweigbergk
manifestdict: extract condition for _intersectfiles() and use for walk()...
r24685 if self._filesfastpath(match):
Martin von Zweigbergk
manifestdict: inline _intersectfiles()...
r24666 m = manifestdict()
lm = self._lm
for fn in match.files():
if fn in lm:
m._lm[fn] = lm[fn]
return m
Martin von Zweigbergk
manifest: add matches() method...
r23305
Martin von Zweigbergk
manifestdict: drop empty-string argument when creating empty manifest...
r24700 m = manifestdict()
Martin von Zweigbergk
manifestdict.matches: avoid name 'lm' for a not-lazymanifest
r24664 m._lm = self._lm.filtercopy(match)
return m
Martin von Zweigbergk
manifest: add matches() method...
r23305
Durham Goode
manifest: add match argument to diff and filesnotin...
r31255 def diff(self, m2, match=None, clean=False):
Augie Fackler
manifest: add optional recording of clean entries to diff...
r23756 '''Finds changes between the current manifest and m2.
Args:
m2: the manifest to which this manifest should be compared.
clean: if true, include files unchanged between these manifests
with a None value in the returned dictionary.
The result is returned as a dict with filename as key and
values of the form ((n1,fl1),(n2,fl2)), where n1/n2 is the
nodeid in the current/other manifest and fl1/fl2 is the flag
in the current/other manifest. Where the file does not exist,
the nodeid will be None and the flags will be the empty
string.
'''
Durham Goode
manifest: add match argument to diff and filesnotin...
r31255 if match:
m1 = self.matches(match)
m2 = m2.matches(match)
return m1.diff(m2, clean=clean)
Augie Fackler
manifest: split manifestdict into high-level and low-level logic...
r24225 return self._lm.diff(m2._lm, clean)
def setflag(self, key, flag):
self._lm[key] = self[key], flag
def get(self, key, default=None):
try:
return self._lm[key][0]
except KeyError:
return default
Martin von Zweigbergk
manifest: for diff(), only iterate over files, not flags...
r22965
Augie Fackler
manifest: split manifestdict into high-level and low-level logic...
r24225 def flags(self, key, default=''):
try:
return self._lm[key][1]
except KeyError:
return default
Martin von Zweigbergk
manifest: for diff(), only iterate over files, not flags...
r22965
Augie Fackler
manifest: split manifestdict into high-level and low-level logic...
r24225 def copy(self):
Martin von Zweigbergk
manifestdict: drop empty-string argument when creating empty manifest...
r24700 c = manifestdict()
Augie Fackler
manifest: split manifestdict into high-level and low-level logic...
r24225 c._lm = self._lm.copy()
return c
Augie Fackler
cleanup: rename all iteritems methods to items and add iteritems alias...
r32550 def items(self):
Martin von Zweigbergk
lazymanifest: make __iter__ generate filenames, not 3-tuples...
r24298 return (x[:2] for x in self._lm.iterentries())
Matt Mackall
Add manifestflags class
r2831
Augie Fackler
cleanup: rename all iteritems methods to items and add iteritems alias...
r32550 iteritems = items
Martin von Zweigbergk
verify: check directory manifests...
r28203 def iterentries(self):
return self._lm.iterentries()
Martin von Zweigbergk
manifestv2: add support for writing new manifest format...
r24573 def text(self, usemanifestv2=False):
if usemanifestv2:
return _textv2(self._lm.iterentries())
else:
# use (probably) native version for v1
return self._lm.text()
Augie Fackler
manifest: move checkforbidden to module-level...
r22408
Augie Fackler
manifest: add fastdelta method to manifestdict...
r22931 def fastdelta(self, base, changes):
Martin von Zweigbergk
manifest: update comment to be about bytearray...
r31787 """Given a base manifest text as a bytearray and a list of changes
Augie Fackler
manifest: add fastdelta method to manifestdict...
r22931 relative to that text, compute a delta that can be used by revlog.
"""
delta = []
dstart = None
dend = None
dline = [""]
start = 0
# zero copy representation of base as a buffer
addbuf = util.buffer(base)
Durham Goode
manifest: skip fastdelta if the change is large...
r26871 changes = list(changes)
if len(changes) < 1000:
# start with a readonly loop that finds the offset of
# each line and creates the deltas
for f, todelete in changes:
# bs will either be the index of the item or the insert point
start, end = _msearch(addbuf, f, start)
if not todelete:
h, fl = self._lm[f]
l = "%s\0%s%s\n" % (f, revlog.hex(h), fl)
else:
if start == end:
# item we want to delete was not found, error out
raise AssertionError(
_("failed to remove %s from manifest") % f)
l = ""
if dstart is not None and dstart <= start and dend >= start:
if dend < end:
dend = end
if l:
dline.append(l)
else:
if dstart is not None:
delta.append([dstart, dend, "".join(dline)])
dstart = start
Augie Fackler
manifest: add fastdelta method to manifestdict...
r22931 dend = end
Durham Goode
manifest: skip fastdelta if the change is large...
r26871 dline = [l]
Augie Fackler
manifest: add fastdelta method to manifestdict...
r22931
Durham Goode
manifest: skip fastdelta if the change is large...
r26871 if dstart is not None:
delta.append([dstart, dend, "".join(dline)])
# apply the delta to the base, and get a delta for addrevision
deltatext, arraytext = _addlistdelta(base, delta)
else:
# For large changes, it's much cheaper to just build the text and
# diff it.
Augie Fackler
py3: use bytearray() instead of array('c', ...) constructions...
r31346 arraytext = bytearray(self.text())
deltatext = mdiff.textdiff(
util.buffer(base), util.buffer(arraytext))
Durham Goode
manifest: skip fastdelta if the change is large...
r26871
Augie Fackler
manifest: add fastdelta method to manifestdict...
r22931 return arraytext, deltatext
Augie Fackler
manifest: move _search to module level and rename to _msearch...
r22930 def _msearch(m, s, lo=0, hi=None):
'''return a tuple (start, end) that says where to find s within m.
If the string is found m[start:end] are the line containing
that string. If start == end the string was not found and
they indicate the proper sorted insertion point.
Yuya Nishihara
py3: fix manifestdict.fastdelta() to be compatible with memoryview...
r31650 m should be a buffer, a memoryview or a byte string.
s is a byte string'''
Augie Fackler
manifest: move _search to module level and rename to _msearch...
r22930 def advance(i, c):
Yuya Nishihara
py3: fix manifestdict.fastdelta() to be compatible with memoryview...
r31650 while i < lenm and m[i:i + 1] != c:
Augie Fackler
manifest: move _search to module level and rename to _msearch...
r22930 i += 1
return i
if not s:
return (lo, lo)
lenm = len(m)
if not hi:
hi = lenm
while lo < hi:
mid = (lo + hi) // 2
start = mid
Yuya Nishihara
py3: fix manifestdict.fastdelta() to be compatible with memoryview...
r31650 while start > 0 and m[start - 1:start] != '\n':
Augie Fackler
manifest: move _search to module level and rename to _msearch...
r22930 start -= 1
end = advance(start, '\0')
Yuya Nishihara
py3: fix manifestdict.fastdelta() to be compatible with memoryview...
r31650 if bytes(m[start:end]) < s:
Augie Fackler
manifest: move _search to module level and rename to _msearch...
r22930 # we know that after the null there are 40 bytes of sha1
# this translates to the bisect lo = mid + 1
lo = advance(end + 40, '\n') + 1
else:
# this translates to the bisect hi = mid
hi = start
end = advance(lo, '\0')
found = m[lo:end]
if s == found:
# we know that after the null there are 40 bytes of sha1
end = advance(end + 40, '\n')
return (lo, end + 1)
else:
return (lo, lo)
Augie Fackler
manifest: mark addlistdelta and checkforbidden as module-private
r22415 def _checkforbidden(l):
Augie Fackler
manifest: move checkforbidden to module-level...
r22408 """Check filenames for illegal characters."""
for f in l:
if '\n' in f or '\r' in f:
raise error.RevlogError(
_("'\\n' and '\\r' disallowed in filenames: %r") % f)
Augie Fackler
manifest: move addlistdelta to module-level...
r22409 # apply the changes collected during the bisect loop to our addlist
# return a delta suitable for addrevision
Augie Fackler
manifest: mark addlistdelta and checkforbidden as module-private
r22415 def _addlistdelta(addlist, x):
Augie Fackler
manifest: move addlistdelta to module-level...
r22409 # for large addlist arrays, building a new array is cheaper
# than repeatedly modifying the existing one
currentposition = 0
Augie Fackler
py3: use bytearray() instead of array('c', ...) constructions...
r31346 newaddlist = bytearray()
Augie Fackler
manifest: move addlistdelta to module-level...
r22409
for start, end, content in x:
newaddlist += addlist[currentposition:start]
if content:
Augie Fackler
py3: use bytearray() instead of array('c', ...) constructions...
r31346 newaddlist += bytearray(content)
Augie Fackler
manifest: move addlistdelta to module-level...
r22409
currentposition = end
newaddlist += addlist[currentposition:]
deltatext = "".join(struct.pack(">lll", start, end, len(content))
+ content for start, end, content in x)
return deltatext, newaddlist
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401 def _splittopdir(f):
if '/' in f:
dir, subpath = f.split('/', 1)
return dir + '/', subpath
else:
return '', f
Augie Fackler
treemanifest: rework lazy-copying code (issue4840)...
r26402 _noop = lambda s: None
Martin von Zweigbergk
treemanifest: lazily load manifests...
r25222
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401 class treemanifest(object):
Martin von Zweigbergk
treemanifest: store directory path in treemanifest nodes...
r24403 def __init__(self, dir='', text=''):
self._dir = dir
Martin von Zweigbergk
treemanifest: store submanifest revlog per directory...
r25091 self._node = revlog.nullid
Augie Fackler
treemanifest: rework lazy-copying code (issue4840)...
r26402 self._loadfunc = _noop
self._copyfunc = _noop
Martin von Zweigbergk
treemanifest: speed up diff by keeping track of dirty nodes...
r25220 self._dirty = False
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401 self._dirs = {}
# Using _lazymanifest here is a little slower than plain old dicts
self._files = {}
self._flags = {}
Martin von Zweigbergk
treemanifest: speed up diff by keeping track of dirty nodes...
r25220 if text:
def readsubtree(subdir, subm):
raise AssertionError('treemanifest constructor only accepts '
'flat manifests')
self.parse(text, readsubtree)
self._dirty = True # Mark flat manifest dirty after parsing
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401
Martin von Zweigbergk
treemanifest: store directory path in treemanifest nodes...
r24403 def _subpath(self, path):
return self._dir + path
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401 def __len__(self):
Martin von Zweigbergk
treemanifest: lazily load manifests...
r25222 self._load()
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401 size = len(self._files)
for m in self._dirs.values():
size += m.__len__()
return size
Drew Gottlieb
treemanifest: add treemanifest._isempty()...
r24551 def _isempty(self):
Martin von Zweigbergk
treemanifest: lazily load manifests...
r25222 self._load() # for consistency; already loaded by all callers
Drew Gottlieb
treemanifest: add treemanifest._isempty()...
r24551 return (not self._files and (not self._dirs or
Augie Fackler
cleanup: use __builtins__.all instead of util.all
r25151 all(m._isempty() for m in self._dirs.values())))
Drew Gottlieb
treemanifest: add treemanifest._isempty()...
r24551
Augie Fackler
manifest: add id(self) to treemanifest __repr__...
r26400 def __repr__(self):
return ('<treemanifest dir=%s, node=%s, loaded=%s, dirty=%s at 0x%x>' %
Martin von Zweigbergk
treemanifest: lazily load manifests...
r25222 (self._dir, revlog.hex(self._node),
Augie Fackler
treemanifest: rework lazy-copying code (issue4840)...
r26402 bool(self._loadfunc is _noop),
Augie Fackler
manifest: add id(self) to treemanifest __repr__...
r26400 self._dirty, id(self)))
Martin von Zweigbergk
treemanifest: store submanifest revlog per directory...
r25091
def dir(self):
'''The directory that this tree manifest represents, including a
trailing '/'. Empty string for the repo root directory.'''
return self._dir
def node(self):
'''This node of this instance. nullid for unsaved instances. Should
be updated when the instance is read or written from a revlog.
'''
Martin von Zweigbergk
treemanifest: speed up diff by keeping track of dirty nodes...
r25220 assert not self._dirty
Martin von Zweigbergk
treemanifest: store submanifest revlog per directory...
r25091 return self._node
def setnode(self, node):
self._node = node
Martin von Zweigbergk
treemanifest: speed up diff by keeping track of dirty nodes...
r25220 self._dirty = False
Martin von Zweigbergk
treemanifest: store directory path in treemanifest nodes...
r24403
Martin von Zweigbergk
treemanifest: implement iterentries()...
r28206 def iterentries(self):
self._load()
Augie Fackler
manifest: use itertools.chain() instead of + for Python 3 compat...
r32536 for p, n in sorted(itertools.chain(self._dirs.items(),
self._files.items())):
Martin von Zweigbergk
treemanifest: implement iterentries()...
r28206 if p in self._files:
yield self._subpath(p), n, self._flags.get(p, '')
else:
for x in n.iterentries():
yield x
Augie Fackler
cleanup: rename all iteritems methods to items and add iteritems alias...
r32550 def items(self):
Martin von Zweigbergk
treemanifest: lazily load manifests...
r25222 self._load()
Augie Fackler
manifest: use itertools.chain() instead of + for Python 3 compat...
r32536 for p, n in sorted(itertools.chain(self._dirs.items(),
self._files.items())):
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401 if p in self._files:
Martin von Zweigbergk
treemanifest: store directory path in treemanifest nodes...
r24403 yield self._subpath(p), n
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401 else:
Martin von Zweigbergk
treemanifest: store directory path in treemanifest nodes...
r24403 for f, sn in n.iteritems():
yield f, sn
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401
Augie Fackler
cleanup: rename all iteritems methods to items and add iteritems alias...
r32550 iteritems = items
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401 def iterkeys(self):
Martin von Zweigbergk
treemanifest: lazily load manifests...
r25222 self._load()
Augie Fackler
manifest: use itertools.chain() instead of + for Python 3 compat...
r32536 for p in sorted(itertools.chain(self._dirs, self._files)):
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401 if p in self._files:
Martin von Zweigbergk
treemanifest: store directory path in treemanifest nodes...
r24403 yield self._subpath(p)
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401 else:
for f in self._dirs[p].iterkeys():
Martin von Zweigbergk
treemanifest: store directory path in treemanifest nodes...
r24403 yield f
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401
def keys(self):
return list(self.iterkeys())
def __iter__(self):
return self.iterkeys()
def __contains__(self, f):
if f is None:
return False
Martin von Zweigbergk
treemanifest: lazily load manifests...
r25222 self._load()
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401 dir, subpath = _splittopdir(f)
if dir:
if dir not in self._dirs:
return False
return self._dirs[dir].__contains__(subpath)
else:
return f in self._files
def get(self, f, default=None):
Martin von Zweigbergk
treemanifest: lazily load manifests...
r25222 self._load()
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401 dir, subpath = _splittopdir(f)
if dir:
if dir not in self._dirs:
return default
return self._dirs[dir].get(subpath, default)
else:
return self._files.get(f, default)
def __getitem__(self, f):
Martin von Zweigbergk
treemanifest: lazily load manifests...
r25222 self._load()
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401 dir, subpath = _splittopdir(f)
if dir:
return self._dirs[dir].__getitem__(subpath)
else:
return self._files[f]
def flags(self, f):
Martin von Zweigbergk
treemanifest: lazily load manifests...
r25222 self._load()
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401 dir, subpath = _splittopdir(f)
if dir:
if dir not in self._dirs:
return ''
return self._dirs[dir].flags(subpath)
else:
if f in self._dirs:
return ''
return self._flags.get(f, '')
def find(self, f):
Martin von Zweigbergk
treemanifest: lazily load manifests...
r25222 self._load()
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401 dir, subpath = _splittopdir(f)
if dir:
return self._dirs[dir].find(subpath)
else:
return self._files[f], self._flags.get(f, '')
def __delitem__(self, f):
Martin von Zweigbergk
treemanifest: lazily load manifests...
r25222 self._load()
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401 dir, subpath = _splittopdir(f)
if dir:
self._dirs[dir].__delitem__(subpath)
# If the directory is now empty, remove it
Drew Gottlieb
treemanifest: add treemanifest._isempty()...
r24551 if self._dirs[dir]._isempty():
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401 del self._dirs[dir]
else:
del self._files[f]
if f in self._flags:
del self._flags[f]
Martin von Zweigbergk
treemanifest: speed up diff by keeping track of dirty nodes...
r25220 self._dirty = True
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401
def __setitem__(self, f, n):
assert n is not None
Martin von Zweigbergk
treemanifest: lazily load manifests...
r25222 self._load()
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401 dir, subpath = _splittopdir(f)
if dir:
if dir not in self._dirs:
Martin von Zweigbergk
treemanifest: store directory path in treemanifest nodes...
r24403 self._dirs[dir] = treemanifest(self._subpath(dir))
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401 self._dirs[dir].__setitem__(subpath, n)
else:
Martin von Zweigbergk
treemanifest: drop 22nd byte for consistency with manifestdict...
r24467 self._files[f] = n[:21] # to match manifestdict's behavior
Martin von Zweigbergk
treemanifest: speed up diff by keeping track of dirty nodes...
r25220 self._dirty = True
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401
Augie Fackler
treemanifest: rework lazy-copying code (issue4840)...
r26402 def _load(self):
if self._loadfunc is not _noop:
lf, self._loadfunc = self._loadfunc, _noop
lf(self)
elif self._copyfunc is not _noop:
cf, self._copyfunc = self._copyfunc, _noop
cf(self)
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401 def setflag(self, f, flags):
"""Set the flags (symlink, executable) for path f."""
Martin von Zweigbergk
treemanifest: lazily load manifests...
r25222 self._load()
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401 dir, subpath = _splittopdir(f)
if dir:
if dir not in self._dirs:
Martin von Zweigbergk
treemanifest: store directory path in treemanifest nodes...
r24403 self._dirs[dir] = treemanifest(self._subpath(dir))
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401 self._dirs[dir].setflag(subpath, flags)
else:
self._flags[f] = flags
Martin von Zweigbergk
treemanifest: speed up diff by keeping track of dirty nodes...
r25220 self._dirty = True
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401
def copy(self):
Martin von Zweigbergk
treemanifest: store directory path in treemanifest nodes...
r24403 copy = treemanifest(self._dir)
Martin von Zweigbergk
treemanifest: store submanifest revlog per directory...
r25091 copy._node = self._node
Martin von Zweigbergk
treemanifest: speed up diff by keeping track of dirty nodes...
r25220 copy._dirty = self._dirty
Augie Fackler
treemanifest: rework lazy-copying code (issue4840)...
r26402 if self._copyfunc is _noop:
def _copyfunc(s):
self._load()
for d in self._dirs:
s._dirs[d] = self._dirs[d].copy()
s._files = dict.copy(self._files)
s._flags = dict.copy(self._flags)
if self._loadfunc is _noop:
_copyfunc(copy)
else:
copy._copyfunc = _copyfunc
else:
copy._copyfunc = self._copyfunc
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401 return copy
Durham Goode
manifest: add match argument to diff and filesnotin...
r31255 def filesnotin(self, m2, match=None):
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401 '''Set of files in this manifest that are not in the other'''
Durham Goode
manifest: add match argument to diff and filesnotin...
r31255 if match:
m1 = self.matches(match)
m2 = m2.matches(match)
return m1.filesnotin(m2)
Martin von Zweigbergk
treemanifest: make filesnotin() faster...
r24405 files = set()
def _filesnotin(t1, t2):
Martin von Zweigbergk
treemanifest: speed up diff by keeping track of dirty nodes...
r25220 if t1._node == t2._node and not t1._dirty and not t2._dirty:
return
Martin von Zweigbergk
treemanifest: lazily load manifests...
r25222 t1._load()
t2._load()
Martin von Zweigbergk
treemanifest: make filesnotin() faster...
r24405 for d, m1 in t1._dirs.iteritems():
if d in t2._dirs:
m2 = t2._dirs[d]
_filesnotin(m1, m2)
else:
files.update(m1.iterkeys())
for fn in t1._files.iterkeys():
if fn not in t2._files:
files.add(t1._subpath(fn))
_filesnotin(self, m2)
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401 return files
@propertycache
def _alldirs(self):
Drew Gottlieb
util: move dirs() and finddirs() from scmutil to util...
r24635 return util.dirs(self)
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401
def dirs(self):
return self._alldirs
def hasdir(self, dir):
Martin von Zweigbergk
treemanifest: lazily load manifests...
r25222 self._load()
Martin von Zweigbergk
treemanifest: make hasdir() faster...
r24406 topdir, subdir = _splittopdir(dir)
if topdir:
if topdir in self._dirs:
return self._dirs[topdir].hasdir(subdir)
return False
return (dir + '/') in self._dirs
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401
Drew Gottlieb
manifest: move changectx.walk() to manifests...
r24646 def walk(self, match):
'''Generates matching file names.
Equivalent to manifest.matches(match).iterkeys(), but without creating
an entirely new manifest.
It also reports nonexistent files by marking them bad with match.bad().
'''
Martin von Zweigbergk
manifest.walk: special-case match.always() for speed...
r24683 if match.always():
for f in iter(self):
yield f
return
Drew Gottlieb
manifest: move changectx.walk() to manifests...
r24646 fset = set(match.files())
Drew Gottlieb
treemanifest: refactor treemanifest.walk()...
r24647 for fn in self._walk(match):
Drew Gottlieb
manifest: move changectx.walk() to manifests...
r24646 if fn in fset:
# specified pattern is the exact name
fset.remove(fn)
Drew Gottlieb
treemanifest: refactor treemanifest.walk()...
r24647 yield fn
Drew Gottlieb
manifest: move changectx.walk() to manifests...
r24646
# for dirstate.walk, files=['.'] means "walk the whole tree".
# follow that here, too
fset.discard('.')
for fn in sorted(fset):
if not self.hasdir(fn):
match.bad(fn, None)
Drew Gottlieb
match: remove unnecessary optimization where visitdir() returns 'all'...
r25188 def _walk(self, match):
'''Recursively generates matching file names for walk().'''
if not match.visitdir(self._dir[:-1] or '.'):
return
Drew Gottlieb
treemanifest: refactor treemanifest.walk()...
r24647
# yield this dir's files and walk its submanifests
Martin von Zweigbergk
treemanifest: lazily load manifests...
r25222 self._load()
Drew Gottlieb
treemanifest: refactor treemanifest.walk()...
r24647 for p in sorted(self._dirs.keys() + self._files.keys()):
if p in self._files:
fullp = self._subpath(p)
if match(fullp):
yield fullp
else:
Drew Gottlieb
match: remove unnecessary optimization where visitdir() returns 'all'...
r25188 for f in self._dirs[p]._walk(match):
Drew Gottlieb
treemanifest: refactor treemanifest.walk()...
r24647 yield f
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401 def matches(self, match):
'''generate a new manifest filtered by the match argument'''
if match.always():
return self.copy()
Drew Gottlieb
treemanifest: make treemanifest.matches() faster...
r24552 return self._matches(match)
Drew Gottlieb
match: remove unnecessary optimization where visitdir() returns 'all'...
r25188 def _matches(self, match):
Drew Gottlieb
treemanifest: make treemanifest.matches() faster...
r24552 '''recursively generate a new manifest filtered by the match argument.
Drew Gottlieb
match: remove unnecessary optimization where visitdir() returns 'all'...
r25188 '''
Martin von Zweigbergk
treemanifest: don't iterate entire matching submanifests on match()...
r27343
visit = match.visitdir(self._dir[:-1] or '.')
if visit == 'all':
return self.copy()
Drew Gottlieb
treemanifest: make treemanifest.matches() faster...
r24552 ret = treemanifest(self._dir)
Martin von Zweigbergk
treemanifest: don't iterate entire matching submanifests on match()...
r27343 if not visit:
Drew Gottlieb
match: remove unnecessary optimization where visitdir() returns 'all'...
r25188 return ret
Drew Gottlieb
treemanifest: make treemanifest.matches() faster...
r24552
Martin von Zweigbergk
treemanifest: lazily load manifests...
r25222 self._load()
Drew Gottlieb
treemanifest: make treemanifest.matches() faster...
r24552 for fn in self._files:
fullp = self._subpath(fn)
if not match(fullp):
continue
ret._files[fn] = self._files[fn]
if fn in self._flags:
ret._flags[fn] = self._flags[fn]
for dir, subm in self._dirs.iteritems():
Drew Gottlieb
match: remove unnecessary optimization where visitdir() returns 'all'...
r25188 m = subm._matches(match)
Drew Gottlieb
treemanifest: make treemanifest.matches() faster...
r24552 if not m._isempty():
ret._dirs[dir] = m
Martin von Zweigbergk
treemanifest: speed up diff by keeping track of dirty nodes...
r25220 if not ret._isempty():
ret._dirty = True
Drew Gottlieb
treemanifest: make treemanifest.matches() faster...
r24552 return ret
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401
Durham Goode
manifest: add match argument to diff and filesnotin...
r31255 def diff(self, m2, match=None, clean=False):
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401 '''Finds changes between the current manifest and m2.
Args:
m2: the manifest to which this manifest should be compared.
clean: if true, include files unchanged between these manifests
with a None value in the returned dictionary.
The result is returned as a dict with filename as key and
values of the form ((n1,fl1),(n2,fl2)), where n1/n2 is the
nodeid in the current/other manifest and fl1/fl2 is the flag
in the current/other manifest. Where the file does not exist,
the nodeid will be None and the flags will be the empty
string.
'''
Durham Goode
manifest: add match argument to diff and filesnotin...
r31255 if match:
m1 = self.matches(match)
m2 = m2.matches(match)
return m1.diff(m2, clean=clean)
Martin von Zweigbergk
treemanifest: make diff() faster...
r24404 result = {}
emptytree = treemanifest()
def _diff(t1, t2):
Martin von Zweigbergk
treemanifest: speed up diff by keeping track of dirty nodes...
r25220 if t1._node == t2._node and not t1._dirty and not t2._dirty:
return
Martin von Zweigbergk
treemanifest: lazily load manifests...
r25222 t1._load()
t2._load()
Martin von Zweigbergk
treemanifest: make diff() faster...
r24404 for d, m1 in t1._dirs.iteritems():
m2 = t2._dirs.get(d, emptytree)
_diff(m1, m2)
for d, m2 in t2._dirs.iteritems():
if d not in t1._dirs:
_diff(emptytree, m2)
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401
Martin von Zweigbergk
treemanifest: make diff() faster...
r24404 for fn, n1 in t1._files.iteritems():
fl1 = t1._flags.get(fn, '')
n2 = t2._files.get(fn, None)
fl2 = t2._flags.get(fn, '')
if n1 != n2 or fl1 != fl2:
result[t1._subpath(fn)] = ((n1, fl1), (n2, fl2))
elif clean:
result[t1._subpath(fn)] = None
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401
Martin von Zweigbergk
treemanifest: make diff() faster...
r24404 for fn, n2 in t2._files.iteritems():
if fn not in t1._files:
fl2 = t2._flags.get(fn, '')
result[t2._subpath(fn)] = ((None, ''), (n2, fl2))
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401
Martin von Zweigbergk
treemanifest: make diff() faster...
r24404 _diff(self, m2)
return result
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401
Martin von Zweigbergk
treemanifest: speed up commit using dirty flag...
r25221 def unmodifiedsince(self, m2):
return not self._dirty and not m2._dirty and self._node == m2._node
Martin von Zweigbergk
treemanifest: store submanifest revlog per directory...
r25091 def parse(self, text, readsubtree):
Martin von Zweigbergk
treemanifest: extract parse method from constructor...
r24781 for f, n, fl in _parse(text):
Martin von Zweigbergk
manifest: use 't' for tree manifest flag...
r27271 if fl == 't':
Martin von Zweigbergk
treemanifest: store submanifest revlog per directory...
r25091 f = f + '/'
self._dirs[f] = readsubtree(self._subpath(f), n)
Martin von Zweigbergk
treemanifest: speed up diff by keeping track of dirty nodes...
r25220 elif '/' in f:
# This is a flat manifest, so use __setitem__ and setflag rather
# than assigning directly to _files and _flags, so we can
# assign a path in a subdirectory, and to mark dirty (compared
# to nullid).
Martin von Zweigbergk
treemanifest: store submanifest revlog per directory...
r25091 self[f] = n
if fl:
self.setflag(f, fl)
Martin von Zweigbergk
treemanifest: speed up diff by keeping track of dirty nodes...
r25220 else:
# Assigning to _files and _flags avoids marking as dirty,
# and should be a little faster.
self._files[f] = n
if fl:
self._flags[f] = fl
Martin von Zweigbergk
treemanifest: extract parse method from constructor...
r24781
Martin von Zweigbergk
manifestv2: add support for writing new manifest format...
r24573 def text(self, usemanifestv2=False):
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401 """Get the full data of this manifest as a bytestring."""
Martin von Zweigbergk
treemanifest: lazily load manifests...
r25222 self._load()
Martin von Zweigbergk
treemanifest: rewrite text() using iterentries()...
r28207 return _text(self.iterentries(), usemanifestv2)
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401
Martin von Zweigbergk
treemanifest: store submanifest revlog per directory...
r25091 def dirtext(self, usemanifestv2=False):
"""Get the full data of this directory as a bytestring. Make sure that
any submanifests have been written first, so their nodeids are correct.
"""
Martin von Zweigbergk
treemanifest: lazily load manifests...
r25222 self._load()
Martin von Zweigbergk
treemanifest: store submanifest revlog per directory...
r25091 flags = self.flags
Martin von Zweigbergk
manifest: use 't' for tree manifest flag...
r27271 dirs = [(d[:-1], self._dirs[d]._node, 't') for d in self._dirs]
Martin von Zweigbergk
treemanifest: store submanifest revlog per directory...
r25091 files = [(f, self._files[f], flags(f)) for f in self._files]
return _text(sorted(dirs + files), usemanifestv2)
Martin von Zweigbergk
treemanifest: lazily load manifests...
r25222 def read(self, gettext, readsubtree):
Augie Fackler
treemanifest: rework lazy-copying code (issue4840)...
r26402 def _load_for_read(s):
s.parse(gettext(), readsubtree)
s._dirty = False
self._loadfunc = _load_for_read
Martin von Zweigbergk
treemanifest: lazily load manifests...
r25222
Martin von Zweigbergk
treemanifest: store submanifest revlog per directory...
r25091 def writesubtrees(self, m1, m2, writesubtree):
Martin von Zweigbergk
treemanifest: lazily load manifests...
r25222 self._load() # for consistency; should never have any effect here
Durham Goode
manifest: call m1.load and m2.load before writing a subtree...
r29888 m1._load()
m2._load()
Martin von Zweigbergk
treemanifest: store submanifest revlog per directory...
r25091 emptytree = treemanifest()
for d, subm in self._dirs.iteritems():
subp1 = m1._dirs.get(d, emptytree)._node
subp2 = m2._dirs.get(d, emptytree)._node
if subp1 == revlog.nullid:
subp1, subp2 = subp2, subp1
writesubtree(subm, subp1, subp2)
Durham Goode
treemanifest: add walksubtrees api...
r31876 def walksubtrees(self, matcher=None):
"""Returns an iterator of the subtrees of this manifest, including this
manifest itself.
If `matcher` is provided, it only returns subtrees that match.
"""
if matcher and not matcher.visitdir(self._dir[:-1] or '.'):
return
if not matcher or matcher(self._dir[:-1]):
yield self
self._load()
for d, subm in self._dirs.iteritems():
for subtree in subm.walksubtrees(matcher=matcher):
yield subtree
Durham Goode
manifest: make manifest derive from manifestrevlog...
r29824 class manifestrevlog(revlog.revlog):
'''A revlog that stores manifest texts. This is responsible for caching the
full-text manifest contents.
'''
Durham Goode
treemanifest: allow manifestrevlog to take an explicit treemanifest arg...
r32252 def __init__(self, opener, dir='', dirlogcache=None, indexfile=None,
treemanifest=False):
Durham Goode
manifest: allow specifying the revlog filename...
r31151 """Constructs a new manifest revlog
`indexfile` - used by extensions to have two manifests at once, like
when transitioning between flatmanifeset and treemanifests.
Durham Goode
treemanifest: allow manifestrevlog to take an explicit treemanifest arg...
r32252
`treemanifest` - used to indicate this is a tree manifest revlog. Opener
options can also be used to make this a tree manifest revlog. The opener
option takes precedence, so if it is set to True, we ignore whatever
value is passed in to the constructor.
Durham Goode
manifest: allow specifying the revlog filename...
r31151 """
Durham Goode
manifest: make manifest derive from manifestrevlog...
r29824 # During normal operations, we expect to deal with not more than four
# revs at a time (such as during commit --amend). When rebasing large
# stacks of commits, the number can go up, hence the config knob below.
cachesize = 4
Durham Goode
treemanifest: allow manifestrevlog to take an explicit treemanifest arg...
r32252 optiontreemanifest = False
Durham Goode
manifest: move revlog specific options from manifest to manifestrevlog...
r29940 usemanifestv2 = False
Durham Goode
manifest: make manifest derive from manifestrevlog...
r29824 opts = getattr(opener, 'options', None)
if opts is not None:
cachesize = opts.get('manifestcachesize', cachesize)
Durham Goode
treemanifest: allow manifestrevlog to take an explicit treemanifest arg...
r32252 optiontreemanifest = opts.get('treemanifest', False)
Durham Goode
manifest: move revlog specific options from manifest to manifestrevlog...
r29940 usemanifestv2 = opts.get('manifestv2', usemanifestv2)
Durham Goode
treemanifest: allow manifestrevlog to take an explicit treemanifest arg...
r32252 self._treeondisk = optiontreemanifest or treemanifest
Durham Goode
manifest: move revlog specific options from manifest to manifestrevlog...
r29940 self._usemanifestv2 = usemanifestv2
Durham Goode
manifest: make manifest derive from manifestrevlog...
r29824 self._fulltextcache = util.lrucachedict(cachesize)
Durham Goode
manifest: move revlog specific options from manifest to manifestrevlog...
r29940 if dir:
assert self._treeondisk, 'opts is %r' % opts
if not dir.endswith('/'):
dir = dir + '/'
Durham Goode
manifest: allow specifying the revlog filename...
r31151
if indexfile is None:
indexfile = '00manifest.i'
if dir:
indexfile = "meta/" + dir + indexfile
Durham Goode
manifest: move revlog specific options from manifest to manifestrevlog...
r29940 self._dir = dir
Durham Goode
manifest: move dirlog up to manifestrevlog...
r29941 # The dirlogcache is kept on the root manifest log
if dir:
self._dirlogcache = dirlogcache
else:
self._dirlogcache = {'': self}
Durham Goode
manifest: move revlog specific options from manifest to manifestrevlog...
r29940
FUJIWARA Katsunori
manifest: specify checkambig=True to revlog.__init__, to avoid ambiguity...
r29998 super(manifestrevlog, self).__init__(opener, indexfile,
FUJIWARA Katsunori
manifest: apply checkambig=True only for root 00manifest.i...
r33172 # only root indexfile is cached
checkambig=not bool(dir))
Durham Goode
manifest: move revlog specific options from manifest to manifestrevlog...
r29940
Durham Goode
manifest: make manifest derive from manifestrevlog...
r29824 @property
def fulltextcache(self):
return self._fulltextcache
def clearcaches(self):
super(manifestrevlog, self).clearcaches()
self._fulltextcache.clear()
Durham Goode
manifest: move dirlog up to manifestrevlog...
r29941 self._dirlogcache = {'': self}
def dirlog(self, dir):
if dir:
assert self._treeondisk
if dir not in self._dirlogcache:
Durham Goode
treemanifest: allow manifestrevlog to take an explicit treemanifest arg...
r32252 mfrevlog = manifestrevlog(self.opener, dir,
self._dirlogcache,
treemanifest=self._treeondisk)
self._dirlogcache[dir] = mfrevlog
Durham Goode
manifest: move dirlog up to manifestrevlog...
r29941 return self._dirlogcache[dir]
Durham Goode
manifest: make manifest derive from manifestrevlog...
r29824
Durham Goode
manifest: remove dependency on manifestrevlog being able to create trees...
r30368 def add(self, m, transaction, link, p1, p2, added, removed, readtree=None):
Durham Goode
manifest: move manifest.add onto manifestrevlog...
r29961 if (p1 in self.fulltextcache and util.safehasattr(m, 'fastdelta')
and not self._usemanifestv2):
# If our first parent is in the manifest cache, we can
# compute a delta here using properties we know about the
# manifest up-front, which may save time later for the
# revlog layer.
_checkforbidden(added)
# combine the changed lists into one sorted iterator
work = heapq.merge([(x, False) for x in added],
[(x, True) for x in removed])
arraytext, deltatext = m.fastdelta(self.fulltextcache[p1], work)
cachedelta = self.rev(p1), deltatext
text = util.buffer(arraytext)
n = self.addrevision(text, transaction, link, p1, p2, cachedelta)
else:
# The first parent manifest isn't already loaded, so we'll
# just encode a fulltext of the manifest and pass that
# through to the revlog layer, and let it handle the delta
# process.
if self._treeondisk:
Durham Goode
manifest: remove dependency on manifestrevlog being able to create trees...
r30368 assert readtree, "readtree must be set for treemanifest writes"
m1 = readtree(self._dir, p1)
m2 = readtree(self._dir, p2)
n = self._addtree(m, transaction, link, m1, m2, readtree)
Durham Goode
manifest: move manifest.add onto manifestrevlog...
r29961 arraytext = None
else:
text = m.text(self._usemanifestv2)
n = self.addrevision(text, transaction, link, p1, p2)
Augie Fackler
py3: use bytearray() instead of array('c', ...) constructions...
r31346 arraytext = bytearray(text)
Durham Goode
manifest: move manifest.add onto manifestrevlog...
r29961
Martin von Zweigbergk
manifest: don't store None in fulltextcache...
r30209 if arraytext is not None:
self.fulltextcache[n] = arraytext
Durham Goode
manifest: move manifest.add onto manifestrevlog...
r29961
return n
Durham Goode
manifest: remove dependency on manifestrevlog being able to create trees...
r30368 def _addtree(self, m, transaction, link, m1, m2, readtree):
Durham Goode
manifest: move manifest.add onto manifestrevlog...
r29961 # If the manifest is unchanged compared to one parent,
# don't write a new revision
Durham Goode
treemanifest: make node reuse match flat manifest behavior...
r31294 if self._dir != '' and (m.unmodifiedsince(m1) or m.unmodifiedsince(m2)):
Durham Goode
manifest: move manifest.add onto manifestrevlog...
r29961 return m.node()
def writesubtree(subm, subp1, subp2):
sublog = self.dirlog(subm.dir())
Durham Goode
manifest: remove dependency on manifestrevlog being able to create trees...
r30368 sublog.add(subm, transaction, link, subp1, subp2, None, None,
readtree=readtree)
Durham Goode
manifest: move manifest.add onto manifestrevlog...
r29961 m.writesubtrees(m1, m2, writesubtree)
text = m.dirtext(self._usemanifestv2)
Durham Goode
treemanifest: make node reuse match flat manifest behavior...
r31294 n = None
if self._dir != '':
# Double-check whether contents are unchanged to one parent
if text == m1.dirtext(self._usemanifestv2):
n = m1.node()
elif text == m2.dirtext(self._usemanifestv2):
n = m2.node()
if not n:
Durham Goode
manifest: move manifest.add onto manifestrevlog...
r29961 n = self.addrevision(text, transaction, link, m1.node(), m2.node())
Durham Goode
treemanifest: make node reuse match flat manifest behavior...
r31294
Durham Goode
manifest: move manifest.add onto manifestrevlog...
r29961 # Save nodeid so parent manifest can calculate its nodeid
m.setnode(n)
return n
Durham Goode
manifest: introduce manifestlog and manifestctx classes...
r29825 class manifestlog(object):
"""A collection class representing the collection of manifest snapshots
referenced by commits in the repository.
In this situation, 'manifest' refers to the abstract concept of a snapshot
of the list of files in the given commit. Consumers of the output of this
class do not care about the implementation details of the actual manifests
they receive (i.e. tree or flat or lazily loaded, etc)."""
Durham Goode
manifest: use property instead of field for manifest revlog storage...
r29826 def __init__(self, opener, repo):
Durham Goode
manifest: move treeinmem onto manifestlog...
r29959 usetreemanifest = False
Durham Goode
manifest: make manifestlog use it's own cache...
r30372 cachesize = 4
Durham Goode
manifest: move treeinmem onto manifestlog...
r29959
opts = getattr(opener, 'options', None)
if opts is not None:
usetreemanifest = opts.get('treemanifest', usetreemanifest)
Durham Goode
manifest: make manifestlog use it's own cache...
r30372 cachesize = opts.get('manifestcachesize', cachesize)
Durham Goode
manifest: move treeinmem onto manifestlog...
r29959 self._treeinmem = usetreemanifest
Martin von Zweigbergk
manifest: remove unused property _oldmanifest...
r32195 self._revlog = repo._constructmanifest()
Durham Goode
manifest: make manifestlog a storecache...
r30219
Durham Goode
manifest: change manifestlog mancache to be directory based...
r30292 # A cache of the manifestctx or treemanifestctx for each directory
self._dirmancache = {}
Durham Goode
manifest: make manifestlog use it's own cache...
r30372 self._dirmancache[''] = util.lrucachedict(cachesize)
Durham Goode
manifest: change manifestlog mancache to be directory based...
r30292
Durham Goode
manifest: make manifestlog use it's own cache...
r30372 self.cachesize = cachesize
Durham Goode
manifest: use property instead of field for manifest revlog storage...
r29826
Durham Goode
manifest: introduce manifestlog and manifestctx classes...
r29825 def __getitem__(self, node):
Durham Goode
manifest: throw LookupError if node not in revlog...
r30290 """Retrieves the manifest instance for the given node. Throws a
LookupError if not found.
Durham Goode
manifest: introduce manifestlog and manifestctx classes...
r29825 """
Durham Goode
manifest: add manifestlog.get to obtain subdirectory instances...
r30291 return self.get('', node)
Durham Goode
manifest: introduce manifestlog and manifestctx classes...
r29825
Durham Goode
manifest: make revlog verification optional...
r30403 def get(self, dir, node, verify=True):
Durham Goode
manifest: add manifestlog.get to obtain subdirectory instances...
r30291 """Retrieves the manifest instance for the given node. Throws a
LookupError if not found.
Durham Goode
manifest: make revlog verification optional...
r30403
`verify` - if True an exception will be thrown if the node is not in
the revlog
Durham Goode
manifest: add manifestlog.get to obtain subdirectory instances...
r30291 """
Durham Goode
manifest: change manifestlog mancache to be directory based...
r30292 if node in self._dirmancache.get(dir, ()):
Martin von Zweigbergk
manifest: remove check for non-contexts in _dirmancache...
r32171 return self._dirmancache[dir][node]
Durham Goode
manifest: change manifestlog mancache to be directory based...
r30292
Durham Goode
manifest: add manifestlog.get to obtain subdirectory instances...
r30291 if dir:
if self._revlog._treeondisk:
Durham Goode
manifest: make revlog verification optional...
r30403 if verify:
dirlog = self._revlog.dirlog(dir)
if node not in dirlog.nodemap:
raise LookupError(node, dirlog.indexfile,
_('no node'))
Durham Goode
manifest: remove _repo from manifestctx objects...
r31153 m = treemanifestctx(self, dir, node)
Durham Goode
manifest: add manifestlog.get to obtain subdirectory instances...
r30291 else:
raise error.Abort(
_("cannot ask for manifest directory '%s' in a flat "
"manifest") % dir)
Durham Goode
manifest: add treemanifestctx class...
r29907 else:
Durham Goode
manifest: make revlog verification optional...
r30403 if verify:
if node not in self._revlog.nodemap:
raise LookupError(node, self._revlog.indexfile,
_('no node'))
Durham Goode
manifest: add manifestlog.get to obtain subdirectory instances...
r30291 if self._treeinmem:
Durham Goode
manifest: remove _repo from manifestctx objects...
r31153 m = treemanifestctx(self, '', node)
Durham Goode
manifest: add manifestlog.get to obtain subdirectory instances...
r30291 else:
Durham Goode
manifest: remove _repo from manifestctx objects...
r31153 m = manifestctx(self, node)
Durham Goode
manifest: change manifestlog mancache to be directory based...
r30292
if node != revlog.nullid:
mancache = self._dirmancache.get(dir)
if not mancache:
mancache = util.lrucachedict(self.cachesize)
self._dirmancache[dir] = mancache
mancache[node] = m
Durham Goode
manifest: introduce manifestlog and manifestctx classes...
r29825 return m
Durham Goode
manifest: move clearcaches to manifestlog...
r30370 def clearcaches(self):
self._dirmancache.clear()
self._revlog.clearcaches()
Durham Goode
manifest: introduce memmanifestctx and memtreemanifestctx...
r30342 class memmanifestctx(object):
Durham Goode
manifest: remove _repo from manifestctx objects...
r31153 def __init__(self, manifestlog):
self._manifestlog = manifestlog
Durham Goode
manifest: introduce memmanifestctx and memtreemanifestctx...
r30342 self._manifestdict = manifestdict()
Durham Goode
manifest: remove manifest.add and add memmfctx.write...
r30345 def _revlog(self):
Durham Goode
manifest: remove _repo from manifestctx objects...
r31153 return self._manifestlog._revlog
Durham Goode
manifest: remove manifest.add and add memmfctx.write...
r30345
Durham Goode
manifest: introduce memmanifestctx and memtreemanifestctx...
r30342 def new(self):
Durham Goode
manifest: remove _repo from manifestctx objects...
r31153 return memmanifestctx(self._manifestlog)
Durham Goode
manifest: introduce memmanifestctx and memtreemanifestctx...
r30342
Durham Goode
manifest: add copy to mfctx classes...
r30343 def copy(self):
Durham Goode
manifest: remove _repo from manifestctx objects...
r31153 memmf = memmanifestctx(self._manifestlog)
Durham Goode
manifest: add copy to mfctx classes...
r30343 memmf._manifestdict = self.read().copy()
return memmf
Durham Goode
manifest: introduce memmanifestctx and memtreemanifestctx...
r30342 def read(self):
return self._manifestdict
Durham Goode
manifest: remove manifest.add and add memmfctx.write...
r30345 def write(self, transaction, link, p1, p2, added, removed):
return self._revlog().add(self._manifestdict, transaction, link, p1, p2,
added, removed)
Durham Goode
manifest: change manifestctx to not inherit from manifestdict...
r29926 class manifestctx(object):
Durham Goode
manifest: introduce manifestlog and manifestctx classes...
r29825 """A class representing a single revision of a manifest, including its
contents, its parent revs, and its linkrev.
"""
Durham Goode
manifest: remove _repo from manifestctx objects...
r31153 def __init__(self, manifestlog, node):
self._manifestlog = manifestlog
Durham Goode
manifest: change manifestctx to not inherit from manifestdict...
r29926 self._data = None
Durham Goode
manifest: introduce manifestlog and manifestctx classes...
r29825
self._node = node
Durham Goode
manifest: add treemanifestctx class...
r29907
# TODO: We eventually want p1, p2, and linkrev exposed on this class,
# but let's add it later when something needs it and we can load it
# lazily.
#self.p1, self.p2 = revlog.parents(node)
#rev = revlog.rev(node)
#self.linkrev = revlog.linkrev(rev)
Durham Goode
manifest: introduce manifestlog and manifestctx classes...
r29825
Durham Goode
manifestctx: add _revlog() function...
r30341 def _revlog(self):
Durham Goode
manifest: remove _repo from manifestctx objects...
r31153 return self._manifestlog._revlog
Durham Goode
manifestctx: add _revlog() function...
r30341
Durham Goode
manifest: introduce manifestlog and manifestctx classes...
r29825 def node(self):
return self._node
Durham Goode
manifest: introduce memmanifestctx and memtreemanifestctx...
r30342 def new(self):
Durham Goode
manifest: remove _repo from manifestctx objects...
r31153 return memmanifestctx(self._manifestlog)
Durham Goode
manifest: introduce memmanifestctx and memtreemanifestctx...
r30342
Durham Goode
manifest: add copy to mfctx classes...
r30343 def copy(self):
Durham Goode
manifest: remove _repo from manifestctx objects...
r31153 memmf = memmanifestctx(self._manifestlog)
Durham Goode
manifest: add copy to mfctx classes...
r30343 memmf._manifestdict = self.read().copy()
return memmf
Mateusz Kwapich
manifest: expose the parents() method
r30565 @propertycache
def parents(self):
return self._revlog().parents(self._node)
Durham Goode
manifest: change manifestctx to not inherit from manifestdict...
r29926 def read(self):
Durham Goode
manifest: check 'if x is None' instead of 'if not x'...
r31097 if self._data is None:
Durham Goode
manifest: change manifestctx to not inherit from manifestdict...
r29926 if self._node == revlog.nullid:
self._data = manifestdict()
else:
Durham Goode
manifestctx: add _revlog() function...
r30341 rl = self._revlog()
Durham Goode
manifest: make manifestctx store the repo...
r30220 text = rl.revision(self._node)
Augie Fackler
py3: use bytearray() instead of array('c', ...) constructions...
r31346 arraytext = bytearray(text)
Durham Goode
manifest: make manifestctx store the repo...
r30220 rl._fulltextcache[self._node] = arraytext
Durham Goode
manifest: change manifestctx to not inherit from manifestdict...
r29926 self._data = manifestdict(text)
return self._data
Durham Goode
manifest: add shallow option to treemanifestctx.readdelta and readfast...
r30293 def readfast(self, shallow=False):
Durham Goode
manifest: get rid of manifest.readshallowfast...
r30294 '''Calls either readdelta or read, based on which would be less work.
readdelta is called if the delta is against the p1, and therefore can be
read quickly.
If `shallow` is True, nothing changes since this is a flat manifest.
'''
Durham Goode
manifestctx: add _revlog() function...
r30341 rl = self._revlog()
Durham Goode
manifest: adds manifestctx.readfast...
r29939 r = rl.rev(self._node)
deltaparent = rl.deltaparent(r)
if deltaparent != revlog.nullrev and deltaparent in rl.parentrevs(r):
return self.readdelta()
return self.read()
Durham Goode
manifest: add shallow option to treemanifestctx.readdelta and readfast...
r30293 def readdelta(self, shallow=False):
Durham Goode
manifest: remove manifest.readshallowdelta...
r30295 '''Returns a manifest containing just the entries that are present
in this manifest, but not in its p1 manifest. This is efficient to read
if the revlog delta is already p1.
Changing the value of `shallow` has no effect on flat manifests.
'''
Durham Goode
manifestctx: add _revlog() function...
r30341 revlog = self._revlog()
Durham Goode
manifest: add manifestctx.readdelta()...
r29938 if revlog._usemanifestv2:
# Need to perform a slow delta
r0 = revlog.deltaparent(revlog.rev(self._node))
Durham Goode
manifest: remove _repo from manifestctx objects...
r31153 m0 = self._manifestlog[revlog.node(r0)].read()
Durham Goode
manifest: add manifestctx.readdelta()...
r29938 m1 = self.read()
md = manifestdict()
for f, ((n0, fl0), (n1, fl1)) in m0.diff(m1).iteritems():
if n1:
md[f] = n1
if fl1:
md.setflag(f, fl1)
return md
r = revlog.rev(self._node)
d = mdiff.patchtext(revlog.revdiff(revlog.deltaparent(r), r))
return manifestdict(d)
Durham Goode
manifest: remove manifest.find...
r30340 def find(self, key):
return self.read().find(key)
Durham Goode
manifest: introduce memmanifestctx and memtreemanifestctx...
r30342 class memtreemanifestctx(object):
Durham Goode
manifest: remove _repo from manifestctx objects...
r31153 def __init__(self, manifestlog, dir=''):
self._manifestlog = manifestlog
Durham Goode
manifest: introduce memmanifestctx and memtreemanifestctx...
r30342 self._dir = dir
self._treemanifest = treemanifest()
Durham Goode
manifest: remove manifest.add and add memmfctx.write...
r30345 def _revlog(self):
Durham Goode
manifest: remove _repo from manifestctx objects...
r31153 return self._manifestlog._revlog
Durham Goode
manifest: remove manifest.add and add memmfctx.write...
r30345
Durham Goode
manifest: introduce memmanifestctx and memtreemanifestctx...
r30342 def new(self, dir=''):
Durham Goode
manifest: remove _repo from manifestctx objects...
r31153 return memtreemanifestctx(self._manifestlog, dir=dir)
Durham Goode
manifest: introduce memmanifestctx and memtreemanifestctx...
r30342
Durham Goode
manifest: add copy to mfctx classes...
r30343 def copy(self):
Durham Goode
manifest: remove _repo from manifestctx objects...
r31153 memmf = memtreemanifestctx(self._manifestlog, dir=self._dir)
Durham Goode
manifest: add copy to mfctx classes...
r30343 memmf._treemanifest = self._treemanifest.copy()
return memmf
Durham Goode
manifest: introduce memmanifestctx and memtreemanifestctx...
r30342 def read(self):
return self._treemanifest
Durham Goode
manifest: remove manifest.add and add memmfctx.write...
r30345 def write(self, transaction, link, p1, p2, added, removed):
Durham Goode
manifest: remove dependency on manifestrevlog being able to create trees...
r30368 def readtree(dir, node):
Durham Goode
manifest: remove _repo from manifestctx objects...
r31153 return self._manifestlog.get(dir, node).read()
Durham Goode
manifest: remove manifest.add and add memmfctx.write...
r30345 return self._revlog().add(self._treemanifest, transaction, link, p1, p2,
Durham Goode
manifest: remove dependency on manifestrevlog being able to create trees...
r30368 added, removed, readtree=readtree)
Durham Goode
manifest: remove manifest.add and add memmfctx.write...
r30345
Durham Goode
manifest: change manifestctx to not inherit from manifestdict...
r29926 class treemanifestctx(object):
Durham Goode
manifest: remove _repo from manifestctx objects...
r31153 def __init__(self, manifestlog, dir, node):
self._manifestlog = manifestlog
Durham Goode
manifest: add treemanifestctx class...
r29907 self._dir = dir
Durham Goode
manifest: change manifestctx to not inherit from manifestdict...
r29926 self._data = None
Durham Goode
manifest: add treemanifestctx class...
r29907
self._node = node
# TODO: Load p1/p2/linkrev lazily. They need to be lazily loaded so that
# we can instantiate treemanifestctx objects for directories we don't
# have on disk.
#self.p1, self.p2 = revlog.parents(node)
#rev = revlog.rev(node)
#self.linkrev = revlog.linkrev(rev)
Durham Goode
manifest: make treemanifestctx store the repo...
r30221 def _revlog(self):
Durham Goode
manifest: remove _repo from manifestctx objects...
r31153 return self._manifestlog._revlog.dirlog(self._dir)
Durham Goode
manifest: make treemanifestctx store the repo...
r30221
Durham Goode
manifest: change manifestctx to not inherit from manifestdict...
r29926 def read(self):
Durham Goode
manifest: check 'if x is None' instead of 'if not x'...
r31097 if self._data is None:
Durham Goode
manifest: make treemanifestctx store the repo...
r30221 rl = self._revlog()
Durham Goode
manifest: change manifestctx to not inherit from manifestdict...
r29926 if self._node == revlog.nullid:
self._data = treemanifest()
Durham Goode
manifest: make treemanifestctx store the repo...
r30221 elif rl._treeondisk:
Durham Goode
manifest: change manifestctx to not inherit from manifestdict...
r29926 m = treemanifest(dir=self._dir)
def gettext():
Durham Goode
manifest: make treemanifestctx store the repo...
r30221 return rl.revision(self._node)
Durham Goode
manifest: change manifestctx to not inherit from manifestdict...
r29926 def readsubtree(dir, subm):
Durham Goode
manifest: change treemanifestctx to construct subtrees from the manifestlog...
r30404 # Set verify to False since we need to be able to create
# subtrees for trees that don't exist on disk.
Durham Goode
manifest: remove _repo from manifestctx objects...
r31153 return self._manifestlog.get(dir, subm, verify=False).read()
Durham Goode
manifest: change manifestctx to not inherit from manifestdict...
r29926 m.read(gettext, readsubtree)
m.setnode(self._node)
self._data = m
else:
Martin von Zweigbergk
treemanifest: fix a "treeinmem" case...
r30338 text = rl.revision(self._node)
Augie Fackler
py3: use bytearray() instead of array('c', ...) constructions...
r31346 arraytext = bytearray(text)
Durham Goode
manifest: make treemanifestctx store the repo...
r30221 rl.fulltextcache[self._node] = arraytext
Durham Goode
manifest: change manifestctx to not inherit from manifestdict...
r29926 self._data = treemanifest(dir=self._dir, text=text)
return self._data
Durham Goode
manifest: add treemanifestctx class...
r29907
def node(self):
return self._node
Durham Goode
manifest: introduce memmanifestctx and memtreemanifestctx...
r30342 def new(self, dir=''):
Durham Goode
manifest: remove _repo from manifestctx objects...
r31153 return memtreemanifestctx(self._manifestlog, dir=dir)
Durham Goode
manifest: introduce memmanifestctx and memtreemanifestctx...
r30342
Durham Goode
manifest: add copy to mfctx classes...
r30343 def copy(self):
Durham Goode
manifest: remove _repo from manifestctx objects...
r31153 memmf = memtreemanifestctx(self._manifestlog, dir=self._dir)
Durham Goode
manifest: add copy to mfctx classes...
r30343 memmf._treemanifest = self.read().copy()
return memmf
Mateusz Kwapich
manifest: expose the parents() method
r30565 @propertycache
def parents(self):
return self._revlog().parents(self._node)
Durham Goode
manifest: add shallow option to treemanifestctx.readdelta and readfast...
r30293 def readdelta(self, shallow=False):
Durham Goode
manifest: remove manifest.readshallowdelta...
r30295 '''Returns a manifest containing just the entries that are present
in this manifest, but not in its p1 manifest. This is efficient to read
if the revlog delta is already p1.
If `shallow` is True, this will read the delta for this directory,
without recursively reading subdirectory manifests. Instead, any
subdirectory entry will be reported as it appears in the manifest, i.e.
the subdirectory will be reported among files and distinguished only by
its 't' flag.
'''
Durham Goode
manifest: make treemanifestctx store the repo...
r30221 revlog = self._revlog()
Durham Goode
manifest: add shallow option to treemanifestctx.readdelta and readfast...
r30293 if shallow and not revlog._usemanifestv2:
r = revlog.rev(self._node)
d = mdiff.patchtext(revlog.revdiff(revlog.deltaparent(r), r))
return manifestdict(d)
else:
# Need to perform a slow delta
r0 = revlog.deltaparent(revlog.rev(self._node))
Durham Goode
manifest: remove _repo from manifestctx objects...
r31153 m0 = self._manifestlog.get(self._dir, revlog.node(r0)).read()
Durham Goode
manifest: add shallow option to treemanifestctx.readdelta and readfast...
r30293 m1 = self.read()
md = treemanifest(dir=self._dir)
for f, ((n0, fl0), (n1, fl1)) in m0.diff(m1).iteritems():
if n1:
md[f] = n1
if fl1:
md.setflag(f, fl1)
return md
Durham Goode
manifest: add manifestctx.readdelta()...
r29938
Durham Goode
manifest: add shallow option to treemanifestctx.readdelta and readfast...
r30293 def readfast(self, shallow=False):
Durham Goode
manifest: get rid of manifest.readshallowfast...
r30294 '''Calls either readdelta or read, based on which would be less work.
readdelta is called if the delta is against the p1, and therefore can be
read quickly.
If `shallow` is True, it only returns the entries from this manifest,
and not any submanifests.
'''
Durham Goode
manifest: make treemanifestctx store the repo...
r30221 rl = self._revlog()
Durham Goode
manifest: adds manifestctx.readfast...
r29939 r = rl.rev(self._node)
deltaparent = rl.deltaparent(r)
Durham Goode
manifest: add shallow option to treemanifestctx.readdelta and readfast...
r30293 if (deltaparent != revlog.nullrev and
deltaparent in rl.parentrevs(r)):
return self.readdelta(shallow=shallow)
if shallow:
return manifestdict(rl.revision(self._node))
else:
return self.read()
Durham Goode
manifest: adds manifestctx.readfast...
r29939
Durham Goode
manifest: remove manifest.find...
r30340 def find(self, key):
return self.read().find(key)