sapling/infinitepush/infinitepushcommands.py
Stanislau Hlebik da308cc725 infinitepush: add metadatafilelimit option
Summary:
Add an option to limit the number of file entries in the metadata field. This
is to avoid huge codemods to eat up all the space.

Depends on D5255883

Test Plan: arc unit

Reviewers: #mercurial, quark

Reviewed By: quark

Subscribers: quark, mjpieters, medson, #sourcecontrol

Differential Revision: https://phabricator.intern.facebook.com/D5264202

Tasks: 19103180

Signature: t1:5264202:1497630109:05d684db34578e309e0bbad314165e66d1f23ce9
2017-06-19 01:27:31 -07:00

99 lines
3.1 KiB
Python

# Copyright 2016 Facebook, Inc.
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
"""
Config::
[infinitepush]
# limit number of files in the node metadata. This is to make sure we don't
# waste too much space on huge codemod commits.
metadatafilelimit = 100
"""
from __future__ import absolute_import
import json
from .backupcommands import cmdtable as backupcmdtable
from mercurial import (
copies as copiesmod,
encoding,
error,
hg,
patch,
registrar,
scmutil,
util,
)
from .common import downloadbundle
from mercurial.node import bin
from mercurial.i18n import _
cmdtable = backupcmdtable
command = registrar.command(cmdtable)
@command('debugfillinfinitepushmetadata',
[('', 'node', [], 'node to fill metadata for')])
def debugfillinfinitepushmetadata(ui, repo, **opts):
'''Special command that fills infinitepush metadata for a node
'''
nodes = opts['node']
if not nodes:
raise error.Abort(_('nodes are not specified'))
filelimit = ui.configint('infinitepush', 'metadatafilelimit', 100)
nodesmetadata = {}
for node in nodes:
index = repo.bundlestore.index
if not bool(index.getbundle(node)):
raise error.Abort(_('node %s is not found') % node)
if node not in repo:
newbundlefile = downloadbundle(repo, bin(node))
bundlepath = "bundle:%s+%s" % (repo.root, newbundlefile)
bundlerepo = hg.repository(ui, bundlepath)
repo = bundlerepo
p1 = repo[node].p1().node()
diffopts = patch.diffallopts(ui, {})
match = scmutil.matchall(repo)
chunks = patch.diff(repo, p1, node, match, None, diffopts, relroot='')
difflines = util.iterlines(chunks)
states = 'modified added removed deleted unknown ignored clean'.split()
status = repo.status(p1, node)
status = zip(states, status)
filestatus = {}
for state, files in status:
for f in files:
filestatus[f] = state
diffstat = patch.diffstatdata(difflines)
changed_files = {}
copies = copiesmod.pathcopies(repo[p1], repo[node])
for filename, adds, removes, isbinary in diffstat[:filelimit]:
# use special encoding that allows non-utf8 filenames
filename = encoding.jsonescape(filename, paranoid=True)
changed_files[filename] = {
'adds': adds, 'removes': removes, 'isbinary': isbinary,
'status': filestatus.get(filename, 'unknown')
}
if filename in copies:
changed_files[filename]['copies'] = copies[filename]
output = {}
output['changed_files'] = changed_files
if len(diffstat) > filelimit:
output['changed_files_truncated'] = True
nodesmetadata[node] = output
with index:
for node, metadata in nodesmetadata.iteritems():
dumped = json.dumps(metadata, sort_keys=True)
index.saveoptionaljsonmetadata(node, dumped)