# -*- coding: utf-8 -*- """ @author: Fabio Erculiani @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 from entropy.i18n import _ from entropy.output import print_error, print_warning, bold, purple, \ teal, blue, darkred, readtext, TextInterface from entropy.const import etpConst, etpUi 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, TransceiverError, PermissionDenied, TransceiverConnectionError, 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 main(): 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: if not cmd_class.ALLOW_UNPRIVILEGED: cmd_class = catch_all allowed = False 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() if allowed: raise SystemExit(exit_st) else: print_error(_("superuser access required")) raise SystemExit(1)