##// END OF EJS Templates
localrepo: introduce "prepushoutgoinghooks" to extend outgoing check easily...
localrepo: introduce "prepushoutgoinghooks" to extend outgoing check easily This patch introduces "prepushoutgoinghooks" to extend outgoing check before pushing changesets to remote easily. This chooses the function returning "util.hooks" instead of the one to be overridden. The latter may cause problems silently, if one of overriders forgets (or fails) to execute a kind of "super(xxx, self).overridden(...)". In the other hand, the former can ensure that all registered functions are invoked, unless one of them raises an exception.

File last commit:

r19230:6d6f148c stable
r21043:6c383c87 default
Show More
blackbox.py
158 lines | 5.1 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)
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)
except OSError, err:
if err.errno != errno.ENOENT:
self.debug("warning: cannot remove '%s': %s\n" %
(newpath, err.strerror))
try:
if newpath:
os.rename(oldpath, newpath)
except OSError, err:
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()
Bryan O'Sullivan
blackbox: defer opening a log file until needed (issue3869)...
r18831 except (IOError, OSError), err:
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: 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:
blackbox.write('%s %s> %s' % (date, user, formattedmsg))
except IOError, err:
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):
Bryan O'Sullivan
blackbox: defer opening a log file until needed (issue3869)...
r18831 self._bbopener = repo.opener
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')
blackbox = repo.opener('blackbox.log', 'r')
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)))