##// END OF EJS Templates
revset: replace extpredicate by revsetpredicate of registrar...
revset: replace extpredicate by revsetpredicate of registrar This patch consists of changes below (these can't be applied separately). - replace revset.extpredicate by registrar.revsetpredicate in extensions - remove setup() on an instance named as revsetpredicate in uisetup()/extsetup() of each extensions registrar.revsetpredicate doesn't have setup() API. - put new entry for revsetpredicate into extraloaders in dispatch This causes implicit loading predicate functions at loading extension. This loading mechanism requires that an extension has an instance named as revsetpredicate, and this is reason why largefiles/__init__.py is also changed in this patch. Before this patch, test-revset.t tests that all decorated revset predicates are loaded by explicit setup() at once ("all or nothing"). Now, test-revset.t tests that any revset predicate isn't loaded at failure of loading extension, because loading itself is executed by dispatch and it can't be controlled on extension side.

File last commit:

r28305:f5ae291d default
r28394:dcb4209b default
Show More
blackbox.py
239 lines | 7.4 KiB | text/x-python | PythonLexer
Bryan O'Sullivan
blackbox: fix copyright
r18676 # blackbox.py - log repository events to a file for post-mortem debugging
Durham Goode
blackbox: adds a blackbox extension...
r18669 #
Bryan O'Sullivan
blackbox: fix copyright
r18676 # Copyright 2010 Nicolas Dumazet
Durham Goode
blackbox: adds a blackbox extension...
r18669 # Copyright 2013 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.
"""log repository events to a blackbox for debugging
Logs event information to .hg/blackbox.log to help debug and diagnose problems.
The events that get logged can be configured via the blackbox.track config key.
timeless
blackbox: log dirty state...
r28246
Takumi IINO
blackbox: fix literal block syntax
r19162 Examples::
Durham Goode
blackbox: adds a blackbox extension...
r18669
[blackbox]
track = *
timeless
blackbox: rewrite dirty documentation noting it is expensive
r28303 # dirty is *EXPENSIVE* (slow);
# each log entry indicates `+` if the repository is dirty, like :hg:`id`.
timeless
blackbox: log dirty state...
r28246 dirty = True
timeless
blackbox: optionally log event source
r28305 # record the source of log messages
logsource = True
Durham Goode
blackbox: adds a blackbox extension...
r18669
[blackbox]
track = command, commandfinish, commandexception, exthook, pythonhook
[blackbox]
track = incoming
Bryan O'Sullivan
blackbox: automatically rotate log files...
r19066 [blackbox]
# limit the size of a log file
maxsize = 1.5 MB
# rotate up to N log files when the current one gets too big
maxfiles = 3
Durham Goode
blackbox: adds a blackbox extension...
r18669 """
Gregory Szorc
blackbox: use absolute_import
r28090 from __future__ import absolute_import
import errno
import re
Durham Goode
blackbox: adds a blackbox extension...
r18669 from mercurial.i18n import _
timeless
blackbox: log working directory version...
r28245 from mercurial.node import hex
Gregory Szorc
blackbox: use absolute_import
r28090 from mercurial import (
cmdutil,
timeless
blackbox: properly replace ui class...
r28248 ui as uimod,
Gregory Szorc
blackbox: use absolute_import
r28090 util,
)
Durham Goode
blackbox: adds a blackbox extension...
r18669
cmdtable = {}
command = cmdutil.command(cmdtable)
Augie Fackler
extensions: document that `testedwith = 'internal'` is special...
r25186 # Note for extension authors: ONLY specify testedwith = 'internal' for
# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
# be specifying the version(s) of Mercurial they are tested with, or
# leave the attribute unspecified.
Durham Goode
blackbox: adds a blackbox extension...
r18669 testedwith = 'internal'
timeless
blackbox: store the blackbox ui object instead of the log file...
r28247 lastui = None
Durham Goode
blackbox: adds a blackbox extension...
r18669
timeless
blackbox: avoid creating multiple file handles for a single log...
r28243 filehandles = {}
def _openlog(vfs):
path = vfs.join('blackbox.log')
if path in filehandles:
return filehandles[path]
filehandles[path] = fp = vfs('blackbox.log', 'a')
return fp
def _closelog(vfs):
path = vfs.join('blackbox.log')
fp = filehandles[path]
del filehandles[path]
fp.close()
Durham Goode
blackbox: adds a blackbox extension...
r18669 def wrapui(ui):
class blackboxui(ui.__class__):
timeless
blackbox: properly replace ui class...
r28248 def __init__(self, src=None):
super(blackboxui, self).__init__(src)
if src is None:
self._partialinit()
else:
self._bbfp = src._bbfp
self._bbrepo = src._bbrepo
self._bbvfs = src._bbvfs
def _partialinit(self):
if util.safehasattr(self, '_bbvfs'):
return
self._bbfp = None
self._bbrepo = None
self._bbvfs = None
def copy(self):
self._partialinit()
return self.__class__(self)
Durham Goode
blackbox: adds a blackbox extension...
r18669 @util.propertycache
def track(self):
Bryan O'Sullivan
blackbox: fix a case of name capture
r19052 return self.configlist('blackbox', 'track', ['*'])
Durham Goode
blackbox: adds a blackbox extension...
r18669
Bryan O'Sullivan
blackbox: automatically rotate log files...
r19066 def _openlogfile(self):
def rotate(oldpath, newpath):
try:
timeless
blackbox: refactor use of vfs as _bbvfs
r28026 self._bbvfs.unlink(newpath)
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except OSError as err:
Bryan O'Sullivan
blackbox: automatically rotate log files...
r19066 if err.errno != errno.ENOENT:
self.debug("warning: cannot remove '%s': %s\n" %
(newpath, err.strerror))
try:
if newpath:
timeless
blackbox: refactor use of vfs as _bbvfs
r28026 self._bbvfs.rename(oldpath, newpath)
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except OSError as err:
Bryan O'Sullivan
blackbox: automatically rotate log files...
r19066 if err.errno != errno.ENOENT:
self.debug("warning: cannot rename '%s' to '%s': %s\n" %
(newpath, oldpath, err.strerror))
timeless
blackbox: avoid creating multiple file handles for a single log...
r28243 fp = _openlog(self._bbvfs)
Bryan O'Sullivan
blackbox: automatically rotate log files...
r19066 maxsize = self.configbytes('blackbox', 'maxsize', 1048576)
if maxsize > 0:
timeless
blackbox: refactor use of vfs as _bbvfs
r28026 st = self._bbvfs.fstat(fp)
Bryan O'Sullivan
blackbox: automatically rotate log files...
r19066 if st.st_size >= maxsize:
path = fp.name
timeless
blackbox: avoid creating multiple file handles for a single log...
r28243 _closelog(self._bbvfs)
Bryan O'Sullivan
blackbox: automatically rotate log files...
r19066 maxfiles = self.configint('blackbox', 'maxfiles', 7)
for i in xrange(maxfiles - 1, 1, -1):
rotate(oldpath='%s.%d' % (path, i - 1),
newpath='%s.%d' % (path, i))
rotate(oldpath=path,
newpath=maxfiles > 0 and path + '.1')
timeless
blackbox: avoid creating multiple file handles for a single log...
r28243 fp = _openlog(self._bbvfs)
Bryan O'Sullivan
blackbox: automatically rotate log files...
r19066 return fp
timeless
blackbox: store the blackbox ui object instead of the log file...
r28247 def _bbwrite(self, fmt, *args):
self._bbfp.write(fmt % args)
self._bbfp.flush()
Durham Goode
blackbox: adds a blackbox extension...
r18669 def log(self, event, *msg, **opts):
timeless
blackbox: store the blackbox ui object instead of the log file...
r28247 global lastui
Durham Goode
blackbox: adds a blackbox extension...
r18669 super(blackboxui, self).log(event, *msg, **opts)
timeless
blackbox: properly replace ui class...
r28248 self._partialinit()
Durham Goode
blackbox: adds a blackbox extension...
r18669
if not '*' in self.track and not event in self.track:
return
timeless
blackbox: properly replace ui class...
r28248 if self._bbfp:
timeless
blackbox: store the blackbox ui object instead of the log file...
r28247 ui = self
timeless
blackbox: properly replace ui class...
r28248 elif self._bbvfs:
Bryan O'Sullivan
blackbox: defer opening a log file until needed (issue3869)...
r18831 try:
timeless
blackbox: rename fp variable
r28244 self._bbfp = self._openlogfile()
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except (IOError, OSError) as err:
Bryan O'Sullivan
blackbox: defer opening a log file until needed (issue3869)...
r18831 self.debug('warning: cannot write to blackbox.log: %s\n' %
err.strerror)
timeless
blackbox: refactor use of vfs as _bbvfs
r28026 del self._bbvfs
timeless
blackbox: rename fp variable
r28244 self._bbfp = None
timeless
blackbox: store the blackbox ui object instead of the log file...
r28247 ui = self
Durham Goode
blackbox: adds a blackbox extension...
r18669 else:
# certain ui instances exist outside the context of
# a repo, so just default to the last blackbox that
# was seen.
timeless
blackbox: store the blackbox ui object instead of the log file...
r28247 ui = lastui
Durham Goode
blackbox: adds a blackbox extension...
r18669
timeless
blackbox: properly replace ui class...
r28248 if ui and ui._bbfp:
Durham Goode
blackbox: adds a blackbox extension...
r18669 date = util.datestr(None, '%Y/%m/%d %H:%M:%S')
Bryan O'Sullivan
blackbox: use util.getuser for portability...
r18787 user = util.getuser()
timeless
util: enable getpid to be replaced...
r28027 pid = str(util.getpid())
Durham Goode
blackbox: adds a blackbox extension...
r18669 formattedmsg = msg[0] % msg[1:]
timeless
blackbox: log working directory version...
r28245 rev = '(unknown)'
timeless
blackbox: log dirty state...
r28246 changed = ''
timeless
blackbox: properly replace ui class...
r28248 if ui._bbrepo:
timeless
blackbox: store the blackbox ui object instead of the log file...
r28247 ctx = ui._bbrepo[None]
timeless
blackbox: remove hexfn...
r28304 parents = ctx.parents()
rev = ('+'.join([hex(p.node()) for p in parents]))
if (ui.configbool('blackbox', 'dirty', False) and (
any(ui._bbrepo.status()) or
any(ctx.sub(s).dirty() for s in ctx.substate)
)):
changed = '+'
timeless
blackbox: optionally log event source
r28305 if ui.configbool('blackbox', 'logsource', False):
src = ' [%s]' % event
else:
src = ''
Bryan O'Sullivan
blackbox: prevent failed I/O from causing hg to abort...
r18786 try:
timeless
blackbox: optionally log event source
r28305 ui._bbwrite('%s %s @%s%s (%s)%s> %s',
date, user, rev, changed, pid, src, formattedmsg)
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except IOError as err:
Bryan O'Sullivan
blackbox: prevent failed I/O from causing hg to abort...
r18786 self.debug('warning: cannot write to blackbox.log: %s\n' %
err.strerror)
timeless
blackbox: properly replace ui class...
r28248 if not lastui or ui._bbrepo:
timeless
blackbox: store the blackbox ui object instead of the log file...
r28247 lastui = ui
Durham Goode
blackbox: adds a blackbox extension...
r18669
def setrepo(self, repo):
timeless
blackbox: properly replace ui class...
r28248 self._bbfp = None
self._bbrepo = repo
timeless
blackbox: refactor use of vfs as _bbvfs
r28026 self._bbvfs = repo.vfs
Durham Goode
blackbox: adds a blackbox extension...
r18669
ui.__class__ = blackboxui
timeless
blackbox: properly replace ui class...
r28248 uimod.ui = blackboxui
Durham Goode
blackbox: adds a blackbox extension...
r18669
def uisetup(ui):
wrapui(ui)
def reposetup(ui, repo):
# During 'hg pull' a httppeer repo is created to represent the remote repo.
# It doesn't have a .hg directory to put a blackbox in, so we don't do
# the blackbox setup for it.
if not repo.local():
return
Durham Goode
blackbox: fix blackbox causing exceptions in tests...
r19230 if util.safehasattr(ui, 'setrepo'):
ui.setrepo(repo)
Durham Goode
blackbox: adds a 'blackbox' command for viewing recent logs...
r18673
@command('^blackbox',
[('l', 'limit', 10, _('the number of events to show')),
],
_('hg blackbox [OPTION]...'))
def blackbox(ui, repo, *revs, **opts):
'''view the recent repository events
'''
timeless
blackbox: refactor use of vfs as _bbvfs
r28026 if not repo.vfs.exists('blackbox.log'):
Durham Goode
blackbox: adds a 'blackbox' command for viewing recent logs...
r18673 return
limit = opts.get('limit')
timeless
blackbox: rename fp variable
r28244 fp = repo.vfs('blackbox.log', 'r')
lines = fp.read().split('\n')
Durham Goode
blackbox: adds a 'blackbox' command for viewing recent logs...
r18673
count = 0
output = []
for line in reversed(lines):
if count >= limit:
break
# count the commands by matching lines like: 2013/01/23 19:13:36 root>
if re.match('^\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} .*> .*', line):
count += 1
output.append(line)
ui.status('\n'.join(reversed(output)))