context: add ctx.files{modified,added,removed}() methods
Changeset-centric copy tracing is currently very slow because it often
reads manifests. One place it needs the manifest is in _chain(), where
it removes a copy X->Y if Y has subsequently gotten removed. I want to
speed that up by keeping track directly in the changeset of which
files are removed in the changeset. These methods will be similar to
ctx.p[12]copies() in that way: they will either read from the
changeset or calculate the information from the manifests otherwise.
Note that these are different from ctx.{modified,added,removed}() on
merge commits. Those functions always compare to p1, but the new ones
compare to both parents. filesadded() means "file does not exist in
either parent but exists now", filesremoved() means "file existed in
either parent but does not exist now", and filesmodified() means "file
existed in either parent and still exists". The set of files in
ctx.files() is the union of the files from the three new functions
(and the three new ones are all disjoint sets).
Also note that uncommitted merges are weird as usual. The invariant
mentioned above still holds, but the functions compare to p1 (and are
thus identical to the existing methods).
Differential Revision: https://phab.mercurial-scm.org/D6367
# Support code for event tracing in Mercurial. Lives in demandimport
# so it can also be used in demandimport.
#
# Copyright 2018 Google LLC.
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
from __future__ import absolute_import
import contextlib
import os
_pipe = None
_checked = False
@contextlib.contextmanager
def log(whencefmt, *whenceargs):
global _pipe, _session, _checked
if _pipe is None:
if _checked:
yield
return
_checked = True
if 'HGCATAPULTSERVERPIPE' not in os.environ:
yield
return
_pipe = open(os.environ['HGCATAPULTSERVERPIPE'], 'w', 1)
_session = os.environ.get('HGCATAPULTSESSION', 'none')
whence = whencefmt % whenceargs
try:
# Both writes to the pipe are wrapped in try/except to ignore
# errors, as we can see mysterious errors in here if the pager
# is active. Presumably other conditions could trigger
# problems too.
try:
_pipe.write('START %s %s\n' % (_session, whence))
except IOError:
pass
yield
finally:
try:
_pipe.write('END %s %s\n' % (_session, whence))
except IOError:
pass