##// END OF EJS Templates
monoblue: add author to filelogentry...
monoblue: add author to filelogentry The line is copied from shortlogentry template.

File last commit:

r26199:5411059d default
r26274:ca60ba39 default
Show More
manifest.py
1020 lines | 32.7 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
Matt Mackall
Simplify i18n imports
r3891 from i18n import _
Drew Gottlieb
util: move dirs() and finddirs() from scmutil to util...
r24635 import mdiff, parsers, error, revlog, util
Simon Heimberg
separate import lines from mercurial and general python modules
r8312 import array, struct
Martin von Zweigbergk
manifestv2: add support for writing new manifest format...
r24573 import os
timeless@mozdev.org
manifest: switch add() to heapq.merge (available in Py2.6+)
r26199 import heapq
mpm@selenic.com
Break apart hg.py...
r1089
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.
if data and data[-1] != '\n':
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:
yield f, revlog.bin(n[:40]), n[40:]
else:
yield f, revlog.bin(n), ''
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.')
stemlen = ord(data[pos])
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)
Augie Fackler
manifest: split manifestdict into high-level and low-level logic...
r24225 class _lazymanifest(dict):
"""This is the pure implementation of lazymanifest.
It has not been optimized *at all* and is not lazy.
"""
Augie Fackler
manifest: move parsing functions up in file...
r24223
Augie Fackler
manifest: split manifestdict into high-level and low-level logic...
r24225 def __init__(self, data):
dict.__init__(self)
Martin von Zweigbergk
manifest: extract method for parsing manifest...
r24524 for f, n, fl in _parse(data):
self[f] = n, fl
Augie Fackler
manifest: do parsing inside manifestdict contstructor...
r24224
Augie Fackler
manifest: disallow setting the node id of an entry to None...
r23594 def __setitem__(self, k, v):
Augie Fackler
manifest: split manifestdict into high-level and low-level logic...
r24225 node, flag = v
assert node is not None
if len(node) > 21:
node = node[:21] # match c implementation behavior
dict.__setitem__(self, k, (node, flag))
def __iter__(self):
Martin von Zweigbergk
lazymanifest: make __iter__ generate filenames, not 3-tuples...
r24298 return iter(sorted(dict.keys(self)))
Augie Fackler
manifest: split manifestdict into high-level and low-level logic...
r24225
Martin von Zweigbergk
lazymanifest: fix pure hg iterkeys()...
r24297 def iterkeys(self):
return iter(sorted(dict.keys(self)))
Martin von Zweigbergk
lazymanifest: make __iter__ generate filenames, not 3-tuples...
r24298 def iterentries(self):
return ((f, e[0], e[1]) for f, e in sorted(self.iteritems()))
Matt Mackall
Add manifestflags class
r2831 def copy(self):
Augie Fackler
manifest: split manifestdict into high-level and low-level logic...
r24225 c = _lazymanifest('')
c.update(self)
return c
def diff(self, m2, clean=False):
'''Finds changes between the current manifest and m2.'''
diff = {}
for fn, e1 in self.iteritems():
if fn not in m2:
diff[fn] = e1, (None, '')
else:
e2 = m2[fn]
if e1 != e2:
diff[fn] = e1, e2
elif clean:
diff[fn] = None
for fn, e2 in m2.iteritems():
if fn not in self:
diff[fn] = (None, ''), e2
return diff
def filtercopy(self, filterfn):
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
def text(self):
"""Get the full data of this manifest as a bytestring."""
Martin von Zweigbergk
manifestv2: add support for writing new manifest format...
r24573 return _textv1(self.iterentries())
Augie Fackler
manifest: split manifestdict into high-level and low-level logic...
r24225
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)
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
Martin von Zweigbergk
copies: move code into new manifestdict.filesnotin() method...
r24184 def filesnotin(self, m2):
'''Set of files in this manifest that are not in the other'''
Martin von Zweigbergk
lazymanifest: make __iter__ generate filenames, not 3-tuples...
r24298 files = set(self)
files.difference_update(m2)
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
Augie Fackler
manifest: add optional recording of clean entries to diff...
r23756 def diff(self, m2, clean=False):
'''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.
'''
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
def iteritems(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
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):
"""Given a base manifest text as an array.array and a list of changes
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)
# 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:
Augie Fackler
manifest: split manifestdict into high-level and low-level logic...
r24225 h, fl = self._lm[f]
l = "%s\0%s%s\n" % (f, revlog.hex(h), fl)
Augie Fackler
manifest: add fastdelta method to manifestdict...
r22931 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
dend = end
dline = [l]
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)
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.
m should be a buffer or a string
s is a string'''
def advance(i, c):
while i < lenm and m[i] != c:
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
while start > 0 and m[start - 1] != '\n':
start -= 1
end = advance(start, '\0')
if m[start:end] < s:
# 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
newaddlist = array.array('c')
for start, end, content in x:
newaddlist += addlist[currentposition:start]
if content:
newaddlist += array.array('c', content)
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
Martin von Zweigbergk
treemanifest: lazily load manifests...
r25222 _noop = lambda: None
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
Martin von Zweigbergk
treemanifest: lazily load manifests...
r25222 self._load = _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
Martin von Zweigbergk
treemanifest: store directory path in treemanifest nodes...
r24403 def __str__(self):
Martin von Zweigbergk
treemanifest: lazily load manifests...
r25222 return ('<treemanifest dir=%s, node=%s, loaded=%s, dirty=%s>' %
(self._dir, revlog.hex(self._node),
bool(self._load is _noop),
self._dirty))
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: create treemanifest class...
r24401 def iteritems(self):
Martin von Zweigbergk
treemanifest: lazily load manifests...
r25222 self._load()
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401 for p, n in sorted(self._dirs.items() + self._files.items()):
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
def iterkeys(self):
Martin von Zweigbergk
treemanifest: lazily load manifests...
r25222 self._load()
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401 for p in sorted(self._dirs.keys() + self._files.keys()):
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
def setflag(self, f, flags):
"""Set the flags (symlink, executable) for path f."""
Martin von Zweigbergk
treemanifest: store submanifest revlog per directory...
r25091 assert 'd' not in flags
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
Martin von Zweigbergk
treemanifest: lazily load manifests...
r25222 def _load():
self._load()
for d in self._dirs:
copy._dirs[d] = self._dirs[d].copy()
copy._files = dict.copy(self._files)
copy._flags = dict.copy(self._flags)
copy._load = _noop
copy._load = _load
if self._load == _noop:
# Chaining _load if it's _noop is functionally correct, but the
# chain may end up excessively long (stack overflow), and
# will prevent garbage collection of 'self'.
copy._load()
Martin von Zweigbergk
treemanifest: create treemanifest class...
r24401 return copy
def filesnotin(self, m2):
'''Set of files in this manifest that are not in the other'''
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 '''
Drew Gottlieb
treemanifest: make treemanifest.matches() faster...
r24552 ret = treemanifest(self._dir)
Drew Gottlieb
match: remove unnecessary optimization where visitdir() returns 'all'...
r25188
if not match.visitdir(self._dir[:-1] or '.'):
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
def diff(self, m2, clean=False):
'''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.
'''
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
treemanifest: store submanifest revlog per directory...
r25091 if fl == 'd':
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
manifest: extract method for creating manifest text...
r24525 flags = self.flags
Martin von Zweigbergk
manifestv2: add support for writing new manifest format...
r24573 return _text(((f, self[f], flags(f)) for f in self.keys()),
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
dirs = [(d[:-1], self._dirs[d]._node, 'd') for d in self._dirs]
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):
def _load():
# Mark as loaded already here, so __setitem__ and setflag() don't
# cause infinite loops when they try to load.
self._load = _noop
self.parse(gettext(), readsubtree)
self._dirty = False
self._load = _load
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
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)
Matt Mackall
revlog: kill from-style imports...
r7634 class manifest(revlog.revlog):
Martin von Zweigbergk
treemanifest: cache directory logs and manifests...
r25185 def __init__(self, opener, dir='', dirlogcache=None):
'''The 'dir' and 'dirlogcache' arguments are for internal use by
manifest.manifest only. External users should create a root manifest
log with manifest.manifest(opener) and call dirlog() on it.
'''
Durham Goode
manifest: make lru size configurable...
r24033 # 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
Martin von Zweigbergk
treemanifest: add configuration for using treemanifest type...
r24402 usetreemanifest = False
Martin von Zweigbergk
manifestv2: add (unused) config option...
r24526 usemanifestv2 = False
Durham Goode
manifest: make lru size configurable...
r24033 opts = getattr(opener, 'options', None)
if opts is not None:
cachesize = opts.get('manifestcachesize', cachesize)
Martin von Zweigbergk
treemanifest: set requires at repo creation time, ignore config after...
r24956 usetreemanifest = opts.get('treemanifest', usetreemanifest)
Martin von Zweigbergk
manifestv2: set requires at repo creation time...
r24571 usemanifestv2 = opts.get('manifestv2', usemanifestv2)
Durham Goode
manifest: make lru size configurable...
r24033 self._mancache = util.lrucachedict(cachesize)
Martin von Zweigbergk
treemanifest: separate flags for trees in memory and trees on disk...
r24701 self._treeinmem = usetreemanifest
self._treeondisk = usetreemanifest
Martin von Zweigbergk
manifestv2: add (unused) config option...
r24526 self._usemanifestv2 = usemanifestv2
Martin von Zweigbergk
treemanifest: store submanifest revlog per directory...
r25091 indexfile = "00manifest.i"
if dir:
assert self._treeondisk
Martin von Zweigbergk
treemanifest: add --dir option to debug{revlog,data,index}...
r25119 if not dir.endswith('/'):
dir = dir + '/'
Martin von Zweigbergk
treemanifest: store submanifest revlog per directory...
r25091 indexfile = "meta/" + dir + "00manifest.i"
revlog.revlog.__init__(self, opener, indexfile)
self._dir = dir
Martin von Zweigbergk
treemanifest: cache directory logs and manifests...
r25185 # The dirlogcache is kept on the root manifest log
if dir:
self._dirlogcache = dirlogcache
else:
self._dirlogcache = {'': self}
Martin von Zweigbergk
treemanifest: add configuration for using treemanifest type...
r24402
def _newmanifest(self, data=''):
Martin von Zweigbergk
treemanifest: separate flags for trees in memory and trees on disk...
r24701 if self._treeinmem:
Martin von Zweigbergk
treemanifest: store submanifest revlog per directory...
r25091 return treemanifest(self._dir, data)
Martin von Zweigbergk
treemanifest: add configuration for using treemanifest type...
r24402 return manifestdict(data)
mpm@selenic.com
Break apart hg.py...
r1089
Martin von Zweigbergk
treemanifest: cache directory logs and manifests...
r25185 def dirlog(self, dir):
assert self._treeondisk
if dir not in self._dirlogcache:
self._dirlogcache[dir] = manifest(self.opener, dir,
self._dirlogcache)
return self._dirlogcache[dir]
Martin von Zweigbergk
manifestv2: implement slow readdelta() without revdiff...
r24528 def _slowreaddelta(self, node):
r0 = self.deltaparent(self.rev(node))
m0 = self.read(self.node(r0))
m1 = self.read(node)
md = self._newmanifest()
for f, ((n0, fl0), (n1, fl1)) in m0.diff(m1).iteritems():
if n1:
md[f] = n1
if fl1:
md.setflag(f, fl1)
return md
Brendan Cully
Abstract manifest block parsing.
r3196 def readdelta(self, node):
Martin von Zweigbergk
treemanifest: separate flags for trees in memory and trees on disk...
r24701 if self._usemanifestv2 or self._treeondisk:
Martin von Zweigbergk
manifestv2: implement slow readdelta() without revdiff...
r24528 return self._slowreaddelta(node)
Matt Mackall
revlog: remove delta function
r7362 r = self.rev(node)
Augie Fackler
manifest: do parsing inside manifestdict contstructor...
r24224 d = mdiff.patchtext(self.revdiff(self.deltaparent(r), r))
Martin von Zweigbergk
treemanifest: add configuration for using treemanifest type...
r24402 return self._newmanifest(d)
Thomas Arendsen Hein
Whitespace/Tab cleanup
r3223
Matt Mackall
manifest: add readfast method
r13711 def readfast(self, node):
Augie Fackler
manifest: document return type of readfast()...
r24925 '''use the faster of readdelta or read
This will return a manifest which is either only the files
added/modified relative to p1, or all files in the
manifest. Which one is returned depends on the codepath used
to retrieve the data.
'''
Matt Mackall
manifest: add readfast method
r13711 r = self.rev(node)
Sune Foldager
revlog: compute correct deltaparent in the deltaparent function...
r14208 deltaparent = self.deltaparent(r)
if deltaparent != revlog.nullrev and deltaparent in self.parentrevs(r):
Matt Mackall
manifest: add readfast method
r13711 return self.readdelta(node)
return self.read(node)
mpm@selenic.com
Break apart hg.py...
r1089 def read(self, node):
Matt Mackall
revlog: kill from-style imports...
r7634 if node == revlog.nullid:
Martin von Zweigbergk
treemanifest: add configuration for using treemanifest type...
r24402 return self._newmanifest() # don't upset local cache
Siddharth Agarwal
manifest: use a size 3 LRU cache to store parsed manifests...
r18604 if node in self._mancache:
return self._mancache[node][0]
Martin von Zweigbergk
treemanifest: store submanifest revlog per directory...
r25091 if self._treeondisk:
Martin von Zweigbergk
treemanifest: lazily load manifests...
r25222 def gettext():
return self.revision(node)
Martin von Zweigbergk
treemanifest: store submanifest revlog per directory...
r25091 def readsubtree(dir, subm):
Martin von Zweigbergk
treemanifest: cache directory logs and manifests...
r25185 return self.dirlog(dir).read(subm)
Martin von Zweigbergk
treemanifest: store submanifest revlog per directory...
r25091 m = self._newmanifest()
Martin von Zweigbergk
treemanifest: lazily load manifests...
r25222 m.read(gettext, readsubtree)
Martin von Zweigbergk
treemanifest: store submanifest revlog per directory...
r25091 m.setnode(node)
arraytext = None
else:
Martin von Zweigbergk
treemanifest: lazily load manifests...
r25222 text = self.revision(node)
Martin von Zweigbergk
treemanifest: store submanifest revlog per directory...
r25091 m = self._newmanifest(text)
arraytext = array.array('c', text)
Martin von Zweigbergk
manifest: rename 'mf', 'map', and 'mapping' to 'm'...
r24147 self._mancache[node] = (m, arraytext)
return m
mpm@selenic.com
Break apart hg.py...
r1089
Vadim Gelfer
fix parsing of tags. make parse errors useful. add new tag tests....
r2320 def find(self, node, f):
'''look up entry for a single file efficiently.
Alexis S. L. Carvalho
fix manifest.find
r4159 return (node, flags) pair if found, (None, None) if not.'''
Martin von Zweigbergk
manifest: rewrite find(node, f) in terms of read(node)...
r24292 m = self.read(node)
Augie Fackler
manifest: split manifestdict into high-level and low-level logic...
r24225 try:
Martin von Zweigbergk
manifest: rewrite find(node, f) in terms of read(node)...
r24292 return m.find(f)
Augie Fackler
manifest: split manifestdict into high-level and low-level logic...
r24225 except KeyError:
Vadim Gelfer
fix parsing of tags. make parse errors useful. add new tag tests....
r2320 return None, None
Martin von Zweigbergk
manifest: rename 'mf', 'map', and 'mapping' to 'm'...
r24147 def add(self, m, transaction, link, p1, p2, added, removed):
Martin von Zweigbergk
treemanifest: separate flags for trees in memory and trees on disk...
r24701 if (p1 in self._mancache and not self._treeinmem
Martin von Zweigbergk
manifestv2: disable fastdelta optimization...
r24527 and not self._usemanifestv2):
Augie Fackler
manifest: rearrange add() method and add comments for clarity...
r22788 # 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.
mpm@selenic.com
Break apart hg.py...
r1089
Augie Fackler
manifest: mark addlistdelta and checkforbidden as module-private
r22415 _checkforbidden(added)
timeless@mozdev.org
manifest: switch add() to heapq.merge (available in Py2.6+)
r26199 # combine the changed lists into one sorted iterator
work = heapq.merge([(x, False) for x in added],
[(x, True) for x in removed])
mpm@selenic.com
Break apart hg.py...
r1089
Martin von Zweigbergk
manifest: rename 'mf', 'map', and 'mapping' to 'm'...
r24147 arraytext, deltatext = m.fastdelta(self._mancache[p1][1], work)
Augie Fackler
manifest: add fastdelta method to manifestdict...
r22931 cachedelta = self.rev(p1), deltatext
Matt Mackall
util: don't mess with builtins to emulate buffer()
r15657 text = util.buffer(arraytext)
Martin von Zweigbergk
manifest: duplicate call to addrevision()...
r24780 n = self.addrevision(text, transaction, link, p1, p2, cachedelta)
Augie Fackler
manifest: rearrange add() method and add comments for clarity...
r22788 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.
Martin von Zweigbergk
treemanifest: store submanifest revlog per directory...
r25091 if self._treeondisk:
m1 = self.read(p1)
m2 = self.read(p2)
n = self._addtree(m, transaction, link, m1, m2)
arraytext = None
else:
text = m.text(self._usemanifestv2)
n = self.addrevision(text, transaction, link, p1, p2)
arraytext = array.array('c', text)
mason@suse.com
Optimize manifest.add...
r1534
Martin von Zweigbergk
manifest: rename 'mf', 'map', and 'mapping' to 'm'...
r24147 self._mancache[n] = (m, arraytext)
mpm@selenic.com
Break apart hg.py...
r1089
return n
Martin von Zweigbergk
treemanifest: store submanifest revlog per directory...
r25091
def _addtree(self, m, transaction, link, m1, m2):
Martin von Zweigbergk
treemanifest: speed up commit using dirty flag...
r25221 # If the manifest is unchanged compared to one parent,
# don't write a new revision
if m.unmodifiedsince(m1) or m.unmodifiedsince(m2):
return m.node()
Martin von Zweigbergk
treemanifest: store submanifest revlog per directory...
r25091 def writesubtree(subm, subp1, subp2):
Martin von Zweigbergk
treemanifest: cache directory logs and manifests...
r25185 sublog = self.dirlog(subm.dir())
Martin von Zweigbergk
treemanifest: store submanifest revlog per directory...
r25091 sublog.add(subm, transaction, link, subp1, subp2, None, None)
m.writesubtrees(m1, m2, writesubtree)
text = m.dirtext(self._usemanifestv2)
Martin von Zweigbergk
treemanifest: speed up commit using dirty flag...
r25221 # Double-check whether contents are unchanged to one parent
Martin von Zweigbergk
treemanifest: store submanifest revlog per directory...
r25091 if text == m1.dirtext(self._usemanifestv2):
n = m1.node()
elif text == m2.dirtext(self._usemanifestv2):
n = m2.node()
else:
n = self.addrevision(text, transaction, link, m1.node(), m2.node())
# Save nodeid so parent manifest can calculate its nodeid
m.setnode(n)
return n