diff --git a/treemanifest/__init__.py b/treemanifest/__init__.py --- a/treemanifest/__init__.py +++ b/treemanifest/__init__.py @@ -718,73 +718,81 @@ ], _('hg backfilltree [OPTIONS]')) def backfilltree(ui, repo, *args, **opts): with repo.wlock(), repo.lock(), repo.transaction('backfilltree') as tr: - _backfill(tr, repo, int(opts.get('limit'))) + start, end = _getbackfillrange(repo, int(opts.get('limit'))) + if start <= end: + mfl = repo.manifestlog + tmfl = mfl.treemanifestlog + revs = repo.revs('%s :: %s' % (start, end)) + _backfilltree(tr, repo, mfl, tmfl, revs) -def _backfill(tr, repo, limit): - ui = repo.ui - cl = repo.changelog - mfl = repo.manifestlog - tmfl = mfl.treemanifestlog - treerevlog = tmfl._revlog - +def _getbackfillrange(repo, limit): + treerevlog = repo.manifestlog.treemanifestlog._revlog maxrev = len(treerevlog) - 1 start = treerevlog.linkrev(maxrev) + 1 - end = min(len(cl), start + limit) - converting = _("converting") - - ui.progress(converting, 0, total=end - start) - for i in xrange(start, end): - ctx = repo[i] - newflat = ctx.manifest() - p1 = ctx.p1() - p2 = ctx.p2() - p1node = p1.manifestnode() - p2node = p2.manifestnode() - if p1node != nullid: - if (p1node not in treerevlog.nodemap or - (p2node != nullid and p2node not in treerevlog.nodemap)): - ui.warn(_("unable to find parent nodes %s %s\n") % (hex(p1node), - hex(p2node))) - return - parentflat = mfl[p1node].read() - parenttree = tmfl[p1node].read() - else: - parentflat = manifest.manifestdict() - parenttree = manifest.treemanifest() - - diff = parentflat.diff(newflat) + numclrevs = len(repo.changelog) + end = min(numclrevs, start + limit) - 1 + return (start, end) - newtree = parenttree.copy() - added = [] - removed = [] - for filename, (old, new) in diff.iteritems(): - if new is not None and new[0] is not None: - added.append(filename) - newtree[filename] = new[0] - newtree.setflag(filename, new[1]) - else: - removed.append(filename) - del newtree[filename] +def _backfilltree(tr, repo, mfl, tmfl, revs): + ui = repo.ui + converting = _("converting flat manifest to tree manifest") + count = 0 + for rev in revs: + ui.progress(converting, count, total=len(revs)) + count = count + 1 - try: - oldaddrevision = treerevlog.addrevision - def addusingnode(*args, **kwargs): - newkwargs = kwargs.copy() - newkwargs['node'] = ctx.manifestnode() - return oldaddrevision(*args, **newkwargs) - treerevlog.addrevision = addusingnode - def readtree(dir, node): - return tmfl.get(dir, node).read() - treerevlog.add(newtree, tr, ctx.rev(), p1node, p2node, added, - removed, readtree=readtree) - finally: - del treerevlog.__dict__['addrevision'] - - ui.progress(converting, i - start, total=end - start) + _converttotree(tr, mfl, tmfl, repo[rev].manifestctx(), rev) ui.progress(converting, None) +def _converttotree(tr, mfl, tmfl, mfctx, rev): + p1node = mfctx.parents[0] + newflat = mfctx.read() + if p1node != nullid: + parentflat = mfl[p1node].read() + parenttree = tmfl[p1node].read() + else: + parentflat = manifest.manifestdict() + parenttree = manifest.treemanifest() + + newtree, added, removed = _getnewtree(newflat, parenttree, parentflat) + _addtotreerevlog(newtree, tr, tmfl, rev, mfctx, added, removed) + +def _getnewtree(newflat, parenttree, parentflat): + diff = parentflat.diff(newflat) + + newtree = parenttree.copy() + added = [] + removed = [] + for filename, (old, new) in diff.iteritems(): + if new is not None and new[0] is not None: + added.append(filename) + newtree[filename] = new[0] + newtree.setflag(filename, new[1]) + else: + removed.append(filename) + del newtree[filename] + + return (newtree, added, removed) + +def _addtotreerevlog(newtree, tr, tmfl, rev, mfctx, added, removed): + try: + p1mf, p2mf = mfctx.parents + treerevlog = tmfl._revlog + oldaddrevision = treerevlog.addrevision + def addusingnode(*args, **kwargs): + newkwargs = kwargs.copy() + newkwargs['node'] = mfctx.node() + return oldaddrevision(*args, **newkwargs) + treerevlog.addrevision = addusingnode + def readtree(dir, node): + return tmfl.get(dir, node).read() + treerevlog.add( + newtree, tr, rev, p1mf, p2mf, added, removed, readtree=readtree) + finally: + del treerevlog.__dict__['addrevision'] + def _unpackmanifestscg3(orig, self, repo, *args, **kwargs): if not treeenabled(repo.ui): return orig(self, repo, *args, **kwargs)