sapling/rage.py

145 lines
4.5 KiB
Python
Raw Normal View History

# Copyright 2014 Facebook Inc.
#
"""log useful diagnostics and file a task to source control oncall"""
from mercurial.i18n import _
from mercurial import cmdutil, util, commands, bookmarks, ui, extensions, error
from hgext import blackbox
import smartlog
import atexit, os, socket, re, time, traceback
cmdtable = {}
command = cmdutil.command(cmdtable)
_failsafeerrors = []
@atexit.register
def _printfailsafeerrors():
if _failsafeerrors:
print('\n'.join(_failsafeerrors))
def _failsafe(func):
try:
return func()
except Exception as ex:
index = len(_failsafeerrors) + 1
message = "[%d]: %s\n%s\n" % (index, str(ex), traceback.format_exc())
_failsafeerrors.append(message)
return '(Failed. See footnote [%d])' % index
@command('^rage',
[('p', 'preview', None,
_('print information generated locally, no paste or task created'))],
_('hg rage'))
def rage(ui, repo, *pats, **opts):
"""log useful diagnostics and file a task to source control oncall
The rage command is for logging useful diagnostics about various
environment information and filing a task to the source control oncall.
The following basic information is included in the task description:
- unixname
- hostname
- repo location
- active bookmark
Your configured editor will be invoked to let you edit the task title
and description.
The following detailed information is uploaded to a Phabricator paste:
- all the basic information (see above)
- 'df -h' output
- 'hg sl' output
- 'hg config'
- first 20 lines of 'hg status'
- last 20 events from 'hg blackbox' ('hg blackbox -l 20')
"""
def format(pair, basic=True):
if basic:
fmt = "%s: %s\n"
else:
fmt = "%s:\n---------------------------\n%s\n"
return fmt % pair
def hgcmd(func, *args, **opts):
ui.pushbuffer()
func(ui, repo, *args, **opts)
return ui.popbuffer()
def shcmd(cmd, input=None, check=True):
_, _, _, p = util.popen4(cmd)
out, err = p.communicate(input)
if check and p.returncode:
raise error.Abort(cmd + ' error: ' + err)
return out
basic = [
('date', time.ctime()),
('unixname', os.getenv('LOGNAME')),
('hostname', socket.gethostname()),
('repo location', _failsafe(lambda: repo.root)),
('active bookmark',
_failsafe(lambda: bookmarks._readactive(repo, repo._bookmarks))),
]
ui._colormode = None
detailed = [
('df -h', _failsafe(lambda: shcmd('df -h', check=False))),
('hg sl', _failsafe(lambda: hgcmd(smartlog.smartlog))),
('hg config', _failsafe(lambda: hgcmd(commands.config))),
('first 20 lines of "hg status"',
_failsafe(lambda:
'\n'.join(hgcmd(commands.status).splitlines()[:20]))),
('hg blackbox -l20',
_failsafe(lambda: hgcmd(blackbox.blackbox, limit=20))),
]
basic_msg = '\n'.join(map(format, basic))
detailed_msg = '\n'.join(map(lambda x: format(x, False), detailed))
if opts.get('preview'):
print(basic_msg + '\n' + detailed_msg)
return
prompt = '''Title: [hg rage] %s on %s by %s
Description:
%s
HG: Edit task title and description. Lines beginning with 'HG:' are removed."
HG: First line is the title followed by the description.
HG: Feel free to add relevant information.
''' % (repo.root, socket.gethostname(), os.getenv('LOGNAME'), basic_msg)
text = re.sub("(?m)^HG:.*(\n|$)", "", ui.edit(prompt, ui.username()))
lines = text.splitlines()
title = re.sub("(?m)^Title:\s+", "", lines[0])
desc = re.sub("(?m)^Description:\s+", "", '\n'.join(lines[1:]))
print 'pasting the rage info:'
paste_url = shcmd('arc paste', desc + detailed_msg).split()[1]
print paste_url
desc += '\ndetailed output @ ' + paste_url
tag = 'hg rage'
oncall = shcmd('oncalls --output unixname source_control').strip()
print 'filing a task for the oncall %s:' % oncall
task_id = shcmd(' '.join([
'tasks',
'create',
'--title=' + util.shellquote(title),
'--pri=low',
'--assign=' + oncall,
'--sub=' + oncall,
'--tag=' + util.shellquote(tag),
'--desc=' + util.shellquote(desc),
])
)
task_num = shcmd('tasks view ' + task_id).splitlines()[0].split()[0]
print 'https://our.intern.facebook.com/intern/tasks/?t=' + task_num