##// END OF EJS Templates
mdiff: don't emit a diff header for empty trivial deltas...
mdiff: don't emit a diff header for empty trivial deltas An empty trivial delta, coded as (0, 0, 0) makes the delta application do nothing, but still takes 12 bytes, while skipping it altogether works as much, without taking any space at all.

File last commit:

r26185:e8f9dffc default
r27711:7a678a12 default
Show More
blackbox.py
164 lines | 5.5 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.
Takumi IINO
blackbox: fix literal block syntax
r19162 Examples::
Durham Goode
blackbox: adds a blackbox extension...
r18669
[blackbox]
track = *
[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 """
from mercurial import util, cmdutil
from mercurial.i18n import _
Bryan O'Sullivan
blackbox: automatically rotate log files...
r19066 import errno, os, re
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'
lastblackbox = None
def wrapui(ui):
class blackboxui(ui.__class__):
@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:
os.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:
os.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))
fp = self._bbopener('blackbox.log', 'a')
maxsize = self.configbytes('blackbox', 'maxsize', 1048576)
if maxsize > 0:
st = os.fstat(fp.fileno())
if st.st_size >= maxsize:
path = fp.name
fp.close()
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')
fp = self._bbopener('blackbox.log', 'a')
return fp
Durham Goode
blackbox: adds a blackbox extension...
r18669 def log(self, event, *msg, **opts):
global lastblackbox
super(blackboxui, self).log(event, *msg, **opts)
if not '*' in self.track and not event in self.track:
return
if util.safehasattr(self, '_blackbox'):
blackbox = self._blackbox
Bryan O'Sullivan
blackbox: defer opening a log file until needed (issue3869)...
r18831 elif util.safehasattr(self, '_bbopener'):
try:
Bryan O'Sullivan
blackbox: automatically rotate log files...
r19066 self._blackbox = 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)
del self._bbopener
self._blackbox = None
blackbox = self._blackbox
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.
blackbox = lastblackbox
if blackbox:
date = util.datestr(None, '%Y/%m/%d %H:%M:%S')
Bryan O'Sullivan
blackbox: use util.getuser for portability...
r18787 user = util.getuser()
Durham Goode
blackbox: add pid to output...
r26185 pid = str(os.getpid())
Durham Goode
blackbox: adds a blackbox extension...
r18669 formattedmsg = msg[0] % msg[1:]
Bryan O'Sullivan
blackbox: prevent failed I/O from causing hg to abort...
r18786 try:
Durham Goode
blackbox: add pid to output...
r26185 blackbox.write('%s %s (%s)> %s' %
(date, user, pid, 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)
Durham Goode
blackbox: adds a blackbox extension...
r18669 lastblackbox = blackbox
def setrepo(self, repo):
Angel Ezquerra
localrepo: remove all external users of localrepo.opener...
r23877 self._bbopener = repo.vfs
Durham Goode
blackbox: adds a blackbox extension...
r18669
ui.__class__ = blackboxui
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
'''
if not os.path.exists(repo.join('blackbox.log')):
return
limit = opts.get('limit')
Angel Ezquerra
localrepo: remove all external users of localrepo.opener...
r23877 blackbox = repo.vfs('blackbox.log', 'r')
Durham Goode
blackbox: adds a 'blackbox' command for viewing recent logs...
r18673 lines = blackbox.read().split('\n')
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)))