# -*- 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 pdb from entropy.i18n import _ from entropy.output import print_error, print_warning, bold, purple, \ teal, blue, darkred, darkgreen, readtext, print_generic, TextInterface, \ is_stdout_a_tty, nocolor from entropy.const import etpConst, const_convert_to_rawstring, \ const_convert_to_unicode, const_debug_enabled, const_mkstemp 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") os._exit(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") os._exit(1) if exc_class is SystemExit: return if exc_class is IOError: if exc_instance.errno != errno.EPIPE: return if exc_class is KeyboardInterrupt: os._exit(1) t_back = entropy.tools.get_traceback(tb_obj = exc_tb) if const_debug_enabled(): 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") os._exit(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") os._exit(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 = const_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") os._exit(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") os._exit(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: os._exit(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(): is_color = "--color" in sys.argv if is_color: sys.argv.remove("--color") if not is_color and not is_stdout_a_tty(): nocolor() 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:] # convert args to unicode, to avoid passing # raw string stuff down to entropy layers def _to_unicode(arg): try: return const_convert_to_unicode( arg, enctype=etpConst['conf_encoding']) except UnicodeDecodeError: print_error("invalid argument: %s" % (arg,)) raise SystemExit(1) args = list(map(_to_unicode, args)) 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] if args: 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)