import os
import sys
import subprocess
import functools
import argcomplete
from argh import ArghParser, named, arg, aliases, expects_obj
import problem
import report as libreport
import reportclient
from reportclient import ask_yes_no, set_verbosity
from abrtcli import config, l18n
from abrtcli.l18n import _
from abrtcli.match import match_completer, match_get_problem
from abrtcli.filtering import (filter_not_reported,
filter_since_timestamp,
filter_until_timestamp)
from abrtcli.utils import (fmt_problems,
remember_cwd,
run_event,
sort_problems)
def arg_verbose(func):
"""
This is a decorator that adds --verbose command line argument to a command.
If the command supports the argument, the command must correctly initialize
reportclient, because we want to propagate the verbosity to called
functions.
"""
@functools.wraps(func)
def abrt_wrapper(args):
if 'verbose' in args:
reportclient.verbose += args.verbose
set_verbosity(reportclient.verbose)
return func(args)
argh_wrapper = arg('-v', '--verbose', action='count', default=0,
help=_('Print verbose information'))
return argh_wrapper(abrt_wrapper)
@aliases('bt')
@expects_obj
@arg('MATCH', nargs='?', default='last', completer=match_completer)
@arg_verbose
def backtrace(args):
prob = match_get_problem(args.MATCH, auth=args.auth)
if hasattr(prob, 'backtrace'):
print(fmt_problems(prob, fmt=config.BACKTRACE_FMT))
else:
print(_('Problem has no backtrace'))
if isinstance(prob, problem.Ccpp):
ret = ask_yes_no(_('Start retracing process?'))
if ret:
retrace(args)
print(fmt_problems(prob, fmt=config.BACKTRACE_FMT))
backtrace.__doc__ = _('Show backtrace of a problem')
@named('debuginfo-install')
@aliases('di')
@expects_obj
@arg('MATCH', nargs='?', default='last', completer=match_completer)
@arg_verbose
def di_install(args):
prob = match_get_problem(args.MATCH, auth=args.auth)
if not isinstance(prob, problem.Ccpp):
which = _('This')
if args.MATCH == 'last':
which = _('Last')
print(_('{} problem is not of a C/C++ type. Can\'t install debuginfo')
.format(which))
sys.exit(1)
prob.chown()
with remember_cwd():
try:
os.chdir(prob.path)
except OSError:
print(_('Permission denied: \'{}\'\n'
'If this is a system problem'
' try running this command as root')
.format(prob.path))
sys.exit(1)
subprocess.call(config.DEBUGINFO_INSTALL_CMD, shell=True)
di_install.__doc__ = _('Install required debuginfo for given problem')
@expects_obj
@arg('-d', '--debuginfo-install', help='Install debuginfo prior launching gdb')
@arg('MATCH', nargs='?', default='last', completer=match_completer)
@arg_verbose
def gdb(args):
prob = match_get_problem(args.MATCH, auth=args.auth)
if not isinstance(prob, problem.Ccpp):
which = 'This'
if args.MATCH == 'last':
which = 'Last'
print('{} problem is not of a C/C++ type. Can\'t run gdb'
.format(which))
sys.exit(1)
prob.chown()
if args.debuginfo_install:
di_install(args)
cmd = config.GDB_CMD.format(di_path=config.DEBUGINFO_PATH)
with remember_cwd():
try:
os.chdir(prob.path)
except OSError:
print(_('Permission denied: \'{}\'\n'
'If this is a system problem'
' try running this command as root')
.format(prob.path))
sys.exit(1)
subprocess.call(cmd, shell=True)
gdb.__doc__ = _('Run GDB against a problem')
@named('list')
@aliases('ls')
@expects_obj
@arg('--since', type=int,
help=_('List only the problems more recent than specified timestamp'))
@arg('--until', type=int,
help=_('List only the problems older than specified timestamp'))
@arg('--fmt', type=str,
help=_('Output format'))
@arg('--pretty', choices=config.FORMATS, default='medium',
help=_('Built-in output format'))
@arg('-n', '--not-reported', default=False,
help=_('List only not-reported problems'))
@arg_verbose
def list_problems(args):
probs = sort_problems(problem.list(auth=args.auth))
if args.since:
probs = filter_since_timestamp(probs, args.since)
if args.until:
probs = filter_until_timestamp(probs, args.until)
if args.not_reported:
probs = filter_not_reported(probs)
if not args.fmt:
fmt = config.MEDIUM_FMT
else:
fmt = args.fmt
if args.pretty != 'medium':
fmt = getattr(config, '{}_FMT'.format(args.pretty.upper()))
out = fmt_problems(probs, fmt=fmt)
if out:
print(out)
else:
print(_('No problems'))
list_problems.__doc__ = _('List problems')
@aliases('show')
@expects_obj
@arg('--fmt', type=str,
help=_('Output format'))
@arg('--pretty', choices=config.FORMATS, default='full',
help=_('Built-in output format'))
@arg('MATCH', nargs='?', default='last', completer=match_completer)
@arg_verbose
def info(args):
prob = match_get_problem(args.MATCH, allow_multiple=True, auth=args.auth)
if not args.fmt:
fmt = config.FULL_FMT
else:
fmt = args.fmt
if args.pretty != 'full':
fmt = getattr(config, '{}_FMT'.format(args.pretty.upper()))
print(fmt_problems(prob, fmt=fmt))
info.__doc__ = _('Print information about problem')
@aliases('rm')
@expects_obj
@arg('MATCH', nargs='?', default='last', completer=match_completer)
@arg('-i', help=_('Prompt before removal'), default=False)
@arg('-f', help=_('Do not prompt before removal'), default=False)
@arg_verbose
def remove(args):
prob = match_get_problem(args.MATCH, auth=args.auth)
print(fmt_problems(prob, fmt=config.FULL_FMT))
ret = True
if not args.f and (args.i or args.MATCH == 'last'):
# force prompt for last problem to avoid accidents
ret = ask_yes_no(_('Are you sure you want to delete this problem?'))
if ret:
prob.delete()
print(_('Removed'))
remove.__doc__ = _('Remove problem')
@expects_obj
@arg('MATCH', nargs='?', default='last', completer=match_completer)
@arg('-u', "--unsafe",
help=_('Ignore security checks to be able to report all problems'),
default=False)
@arg_verbose
def report(args):
prob = match_get_problem(args.MATCH, auth=args.auth)
if prob.not_reportable and not args.unsafe:
if reportclient.verbose > 0:
print(prob.not_reportable_reason)
print(_('Problem \'{0}\' cannot be reported').format(prob.short_id))
sys.exit(1)
flags = libreport.LIBREPORT_WAIT | libreport.LIBREPORT_RUN_CLI
if args.unsafe:
flags |= libreport.LIBREPORT_IGNORE_NOT_REPORTABLE
prob.chown()
libreport.report_problem_in_dir(prob.path, flags)
report.__doc__ = _('Report problem')
@expects_obj
@arg('-l', '--local', action='store_true',
help=_('Perform local retracing'))
@arg('-r', '--remote', action='store_true',
help=_('Perform remote retracing using retrace server'))
@arg('-f', '--force', action='store_true',
help=_('Force retracing even if backtrace already exists'))
@arg('MATCH', nargs='?', default='last', completer=match_completer)
@arg_verbose
def retrace(args):
# we might not get these var if called from backtrace
local, remote, auth = False, False, False
if hasattr(args, 'local'):
local = args.local
if hasattr(args, 'remote'):
remote = args.remote
if hasattr(args, 'force'):
force = args.force
prob = match_get_problem(args.MATCH, auth=args.auth)
if hasattr(prob, 'backtrace') and not force:
print(_('Problem already has a backtrace'))
print(_('Run abrt retrace with -f/--force to retrace again'))
ret = ask_yes_no(_('Show backtrace?'))
if ret:
print(fmt_problems(prob, fmt=config.BACKTRACE_FMT))
elif not isinstance(prob, problem.Ccpp):
print(_('No retracing possible for this problem type'))
else:
if not (local or remote): # ask..
ret = ask_yes_no(
_('Upload core dump and perform remote'
' retracing? (It may contain sensitive data).'
' If your answer is \'No\', a stack trace will'
' be generated locally. Local retracing'
' requires downloading potentially large amount'
' of debuginfo data'))
if ret:
remote = True
else:
local = True
prob.chown()
if remote:
print(_('Remote retracing'))
run_event('analyze_RetraceServer', prob)
else:
print(_('Local retracing'))
run_event('analyze_LocalGDB', prob)
retrace.__doc__ = _('Generate backtrace from coredump')
@expects_obj
@arg('-b', '--bare',
help=_('Print only the problem count without any message'))
@arg('-s', '--since', type=int,
help=_('Print only the problems more recent than specified timestamp'))
@arg('-n', '--not-reported', default=False,
help=_('List only not-reported problems'))
@arg_verbose
def status(args):
probs = problem.list(auth=args.auth)
since_append = ''
if args.since:
probs = filter_since_timestamp(probs, args.since)
since_append = ' --since {}'.format(args.since)
if args.not_reported:
probs = filter_not_reported(probs)
if args.bare:
print(len(probs))
return
print(_('ABRT has detected {} problem(s). For more info run: abrt list{}')
.format(len(probs), since_append))
status.__doc__ = _('Print count of the recent crashes')
def main():
l18n.init()
parser = ArghParser()
parser.add_argument('-a', '--auth',
action='store_true',
help=_('Authenticate and show all problems'
' on this machine'))
parser.add_argument('-v', '--version',
action='version',
version=config.VERSION)
parser.add_commands([
backtrace,
di_install,
gdb,
info,
list_problems,
remove,
report,
retrace,
status,
])
argcomplete.autocomplete(parser)
try:
parser.dispatch()
except KeyboardInterrupt:
sys.exit(1)
sys.exit(0)