Files
entropy/client/solo/main.py
Fabio Erculiani 12221f6e2e [Solo] try parsing arguments even when superuser access is required
This makes possible to print possible parser error messages without
requiring superuser credentials.
2012-09-30 09:40:17 +02:00

330 lines
9.9 KiB
Python

# -*- coding: utf-8 -*-
"""
@author: Fabio Erculiani <lxnay@sabayon.org>
@contact: lxnay@sabayon.org
@copyright: Fabio Erculiani
@license: GPL-2
B{Entropy Command Line Client}.
"""
import os
import sys
import errno
import tempfile
import argparse
import pdb
from entropy.i18n import _
from entropy.output import print_error, print_warning, bold, purple, \
teal, blue, darkred, darkgreen, readtext, print_generic, TextInterface
from entropy.const import etpConst, etpUi, const_convert_to_rawstring
from entropy.exceptions import SystemDatabaseError, OnlineMirrorError, \
RepositoryError, PermissionDenied, FileNotFound, SPMError
import entropy.tools
from solo.commands.descriptor import SoloCommandDescriptor
from solo.utils import read_client_release
def handle_exception(exc_class, exc_instance, exc_tb):
# restore original exception handler, to avoid loops
uninstall_exception_handler()
_text = TextInterface()
if exc_class is SystemDatabaseError:
_text.output(
darkred(_("Installed packages repository corrupted. "
"Please re-generate it")),
importance=1,
level="error")
raise SystemExit(101)
generic_exc_classes = (OnlineMirrorError, RepositoryError,
PermissionDenied, FileNotFound, SPMError, SystemError)
if exc_class in generic_exc_classes:
_text.output(
"%s: %s" % (exc_instance, darkred(_("Cannot continue")),),
importance=1,
level="error")
raise SystemExit(1)
if exc_class is SystemExit:
return
if exc_class is IOError:
if exc_instance.errno != errno.EPIPE:
return
if exc_class is KeyboardInterrupt:
raise SystemExit(1)
t_back = entropy.tools.get_traceback(tb_obj = exc_tb)
if etpUi['debug']:
sys.stdout = sys.__stdout__
sys.stderr = sys.__stderr__
sys.stdin = sys.__stdin__
entropy.tools.print_exception(tb_data = exc_tb)
pdb.set_trace()
if exc_class is OSError:
if exc_instance.errno == errno.ENOSPC:
print_generic(t_back)
_text.output(
"%s: %s" % (
exc_instance,
darkred(_("Your hard drive is full! Your fault!")),),
importance=1,
level="error")
raise SystemExit(5)
elif exc_instance.errno == errno.ENOMEM:
print_generic(t_back)
_text.output(
"%s: %s" % (
exc_instance,
darkred(_("No more memory dude! Your fault!")),),
importance=1,
level="error")
raise SystemExit(5)
_text.output(
darkred(_("Hi. My name is Bug Reporter. "
"I am sorry to inform you that the program crashed. "
"Well, you know, shit happens.")),
importance=1,
level="error")
_text.output(
darkred(_("But there's something you could "
"do to help me to be a better application.")),
importance=1,
level="error")
_text.output(
darkred(
_("-- BUT, DO NOT SUBMIT THE SAME REPORT MORE THAN ONCE --")),
importance=1,
level="error")
_text.output(
darkred(
_("Now I am showing you what happened. "
"Don't panic, I'm here to help you.")),
importance=1,
level="error")
entropy.tools.print_exception(tb_data = exc_tb)
exception_data = entropy.tools.print_exception(silent = True,
tb_data = exc_tb, all_frame_data = True)
exception_tback_raw = const_convert_to_rawstring(t_back)
error_fd, error_file = None, None
try:
error_fd, error_file = tempfile.mkstemp(
prefix="entropy.error.report.",
suffix=".txt")
with os.fdopen(error_fd, "wb") as ferror:
ferror.write(
const_convert_to_rawstring(
"\nRevision: %s\n\n" % (
etpConst['entropyversion'],))
)
ferror.write(
exception_tback_raw)
ferror.write(
const_convert_to_rawstring("\n\n"))
ferror.write(
const_convert_to_rawstring(''.join(exception_data)))
ferror.write(
const_convert_to_rawstring("\n"))
except (OSError, IOError) as err:
_text.output(
"%s: %s" % (
err,
darkred(
_("Oh well, I cannot even write to TMPDIR. "
"So, please copy the error and "
"mail lxnay@sabayon.org."))),
importance=1,
level="error")
raise SystemExit(1)
finally:
if error_fd is not None:
try:
os.close(error_fd)
except OSError:
pass
_text.output("", level="error")
ask_msg = _("Erm... Can I send the error, "
"along with some other information\nabout your "
"hardware to my creators so they can fix me? "
"(Your IP will be logged)")
rc = _text.ask_question(ask_msg)
if rc == _("No"):
_text.output(
darkgreen(_("Ok, ok ok ok... Sorry!")),
level="error")
raise SystemExit(2)
_text.output(
darkgreen(
_("If you want to be contacted back "
"(and actively supported), also answer "
"the questions below:")
),
level="error")
try:
name = readtext(_("Your Full name:"))
email = readtext(_("Your E-Mail address:"))
description = readtext(_("What you were doing:"))
except EOFError:
raise SystemExit(2)
try:
from entropy.client.interfaces.qa import UGCErrorReportInterface
from entropy.core.settings.base import SystemSettings
_settings = SystemSettings()
repository_id = _settings['repositories']['default_repository']
error = UGCErrorReportInterface(repository_id)
except (OnlineMirrorError, AttributeError, ImportError,):
error = None
result = None
if error is not None:
error.prepare(exception_tback_raw, name, email,
'\n'.join([x for x in exception_data]), description)
result = error.submit()
if result:
_text.output(
darkgreen(
_("Thank you very much. The error has been "
"reported and hopefully, the problem will "
"be solved as soon as possible.")),
level="error")
else:
_text.output(
darkred(_("Ugh. Cannot send the report. "
"Please mail the file below "
"to lxnay@sabayon.org.")),
level="error")
_text.output("", level="error")
_text.output("==> %s" % (error_file,), level="error")
_text.output("", level="error")
def install_exception_handler():
sys.excepthook = handle_exception
def uninstall_exception_handler():
sys.excepthook = sys.__excepthook__
def warn_version_mismatch():
equo_ver = read_client_release()
entropy_ver = etpConst['entropyversion']
if equo_ver != entropy_ver:
print_warning("")
print_warning("%s: %s" % (
bold(_("Entropy/Equo version mismatch")),
purple(_("it could make your system explode!")),))
print_warning("(%s [equo] & %s [entropy])" % (
blue(equo_ver),
blue(entropy_ver),))
print_warning("")
def warn_live_system():
print_warning("")
print_warning(
purple(_("Entropy is running off a Live System")))
print_warning(
teal(_("Performance and stability could get"
" severely compromised")))
print_warning("")
def main():
warn_version_mismatch()
install_exception_handler()
descriptors = SoloCommandDescriptor.obtain()
args_map = {}
catch_all = None
for descriptor in descriptors:
klass = descriptor.get_class()
if klass.CATCH_ALL:
catch_all = klass
args_map[klass.NAME] = klass
for alias in klass.ALIASES:
args_map[alias] = klass
args = sys.argv[1:]
is_bashcomp = False
if "--bashcomp" in args:
is_bashcomp = True
args.remove("--bashcomp")
# the first eit, because bash does:
# argv -> equo --bashcomp equo repo
# and we need to drop --bashcomp and
# argv[2]
args.pop(0)
cmd = None
last_arg = None
if args:
last_arg = args[-1]
cmd = args[0]
args = args[1:]
cmd_class = args_map.get(cmd)
yell_class = args_map.get("yell")
if cmd_class is None:
cmd_class = catch_all
cmd_obj = cmd_class(args)
if is_bashcomp:
try:
cmd_obj.bashcomp(last_arg)
except NotImplementedError:
pass
raise SystemExit(0)
# non-root users not allowed
allowed = True
if os.getuid() != 0 and \
cmd_class is not catch_all and \
not cmd_class.ALLOW_UNPRIVILEGED and \
"--help" not in args:
cmd_class = catch_all
allowed = False
if allowed:
if not cmd_class.ALLOW_UNPRIVILEGED:
if entropy.tools.islive():
warn_live_system()
func, func_args = cmd_obj.parse()
exit_st = func(*func_args)
if exit_st == -10:
# syntax error, yell at user
func, func_args = yell_class(args).parse()
func(*func_args)
raise SystemExit(10)
else:
yell_class.reset()
raise SystemExit(exit_st)
else:
# execute this anyway so that commands are
# incomplete or invalid, the command error
# message will take precedence.
_func, _func_args = cmd_obj.parse()
print_error(_("superuser access required"))
raise SystemExit(1)