Esempio n. 1
0
def raise_and_clear_error():
    """Raises an error if there is one. Calling this will clear the error
    so a second call won't do anything.

    enable() needs to be called first.

    Raises:
        FaultHandlerCrash
    """

    global _fileobj

    if _fileobj is None:
        return

    try:
        _fileobj.seek(0)
        text = _fileobj.read().decode("utf-8", "replace").strip()
        _fileobj.seek(0)
        _fileobj.truncate()
    except IOError:
        print_exc()
    else:
        if text:
            raise FaultHandlerCrash(text)
Esempio n. 2
0
def dump_to_disk(dump_dir, exc_info):
    """Writes a new error log file into 'dump_dir'

    Args:
        dump_dir (path-like)
        exc_info (tuple): sys.exc_info() result tuple
    """

    try:
        mkdir(dump_dir)
    except EnvironmentError:
        print_exc()
        return

    time_ = time.localtime()
    dump_path = os.path.join(
        dump_dir, time.strftime("Dump_%Y%m%d_%H%M%S.txt", time_))

    header = format_dump_header(exc_info).encode("utf-8")
    log = format_dump_log().encode("utf-8")

    try:
        with open(dump_path, "wb") as dump:
            dump.write(header)
            dump.write(log)
    except EnvironmentError:
        print_exc()
Esempio n. 3
0
def errorhook(exc_info=None):
    """This is the main entry point

    Call in an exception context. Thread safe.

    def my_thread():
        try:
            do_work()
        except Exception:
            errorhook()
    """

    global _error_lock, _errorhook_enabled

    if not _errorhook_enabled:
        return

    if exc_info is None:
        exc_info = sys.exc_info()

    if exc_info[0] is None:
        # called outside of an exception context, just ignore
        print_e("no active exception!")
        return

    # In case something goes wrong during error handling print it first
    print_exc(exc_info)

    if not _error_lock.acquire(False):
        # Make sure only one of these is active at a time
        return

    # write error and logs to disk
    dump_dir = os.path.join(quodlibet.get_user_dir(), "dumps")
    dump_to_disk(dump_dir, exc_info)

    sentry = get_sentry()

    # For crashes the stack trace is not enough to differentiating different
    # crash sources. We need to give our own grouping key (fingerprint) based
    # on the stack trace provided by faulthandler.
    fingerprint = None
    if isinstance(exc_info[1], FaultHandlerCrash):
        fingerprint = ["{{ default }}", exc_info[1].get_grouping_key()]

    try:
        sentry_error = sentry.capture(exc_info, fingerprint=fingerprint)
    except SentryError:
        sentry_error = None

    def called_in_main_thread():
        try:
            run_error_dialogs(exc_info, sentry_error)
        finally:
            _error_lock.release()

    if is_main_thread():
        called_in_main_thread()
    else:
        GLib.idle_add(called_in_main_thread)
Esempio n. 4
0
def raise_and_clear_error():
    """Raises an error if there is one. Calling this will clear the error
    so a second call wont do anything.

    enable() needs to be called first.

    Raises:
        FaultHandlerCrash
    """

    global _fileobj

    if _fileobj is None:
        return

    try:
        _fileobj.seek(0)
        text = _fileobj.read().decode("utf-8", "replace").strip()
        _fileobj.seek(0)
        _fileobj.truncate()
    except IOError:
        print_exc()
    else:
        if text:
            raise FaultHandlerCrash(text)
Esempio n. 5
0
def errorhook(exc_info=None):
    """This is the main entry point

    Call in an exception context. Thread safe.

    def my_thread():
        try:
            do_work()
        except Exception:
            errorhook()
    """

    global _error_lock, _errorhook_enabled

    if not _errorhook_enabled:
        return

    if exc_info is None:
        exc_info = sys.exc_info()

    if exc_info[0] is None:
        # called outside of an exception context, just ignore
        print_e("no active exception!")
        return

    # In case something goes wrong during error handling print it first
    print_exc(exc_info)

    if not _error_lock.acquire(False):
        # Make sure only one of these is active at a time
        return

    # write error and logs to disk
    dump_dir = os.path.join(quodlibet.get_user_dir(), "dumps")
    dump_to_disk(dump_dir, exc_info)

    sentry = get_sentry()

    # For crashes the stack trace is not enough to differentiating different
    # crash sources. We need to give our own grouping key (fingerprint) based
    # on the stack trace provided by faulthandler.
    fingerprint = None
    if isinstance(exc_info[1], FaultHandlerCrash):
        fingerprint = ["{{ default }}", exc_info[1].get_grouping_key()]

    try:
        sentry_error = sentry.capture(exc_info, fingerprint=fingerprint)
    except SentryError:
        sentry_error = None

    def called_in_main_thread():
        try:
            run_error_dialogs(exc_info, sentry_error)
        finally:
            _error_lock.release()

    if is_main_thread():
        called_in_main_thread()
    else:
        GLib.idle_add(called_in_main_thread)
Esempio n. 6
0
def website(site):
    """Open the given URL in the user's default browser"""

    from gi.repository import Gtk, Gdk, GLib

    try:
        Gtk.show_uri(None, site, Gdk.CURRENT_TIME)
    except GLib.Error:
        print_exc()
Esempio n. 7
0
def website(site):
    """Open the given URL in the user's default browser"""

    from gi.repository import Gtk, Gdk, GLib

    try:
        Gtk.show_uri(None, site, Gdk.CURRENT_TIME)
    except GLib.Error:
        print_exc()
Esempio n. 8
0
def run_error_dialogs(exc_info, sentry_error):
    error_text = u"%s: %s" % (exc_info[0].__name__,
                              (text_type(exc_info[1]).strip()
                               or u"\n").splitlines()[0])
    error_text += u"\n------\n"
    error_text += u"\n".join(format_exception(*exc_info))

    # Don't reshow the error dialog in case the user wanted to quit the app
    # but due to the error state more errors pile up..
    if app.is_quitting:
        return

    window = find_active_window()
    if window is None:
        return

    # XXX: This does blocking IO and uses nested event loops... but it's simple
    dialog = ErrorDialog(window,
                         error_text,
                         show_bug_report=(sentry_error is None))
    while 1:
        response = dialog.run()
        if response == ErrorDialog.RESPONSE_QUIT:
            dialog.destroy()
            app.quit()
        elif response == ErrorDialog.RESPONSE_SUBMIT:
            dialog.hide()
            submit_dialog = SubmitErrorDialog(window,
                                              sentry_error.get_report())
            submit_response = submit_dialog.run()

            if submit_response == SubmitErrorDialog.RESPONSE_SUBMIT:
                sentry_error.set_comment(submit_dialog.get_comment())
                timeout_seconds = 5
                try:
                    sentry_error.send(timeout_seconds)
                except SentryError:
                    print_exc()
                submit_dialog.destroy()
                dialog.destroy()
            else:
                submit_dialog.destroy()
                dialog.show()
                continue
        elif response == ErrorDialog.RESPONSE_BUGREPORT:
            url = get_github_issue_url(exc_info)
            website(url)
            dialog.destroy()
        else:
            dialog.destroy()
        break
Esempio n. 9
0
def run_error_dialogs(exc_info, sentry_error):
    assert sentry_error is not None

    error_text = u"%s: %s" % (
        exc_info[0].__name__,
        (text_type(exc_info[1]).strip() or u"\n").splitlines()[0])
    error_text += u"\n------\n"
    error_text += u"\n".join(format_exception(*exc_info))

    # Don't reshow the error dialog in case the user wanted to quit the app
    # but due to the error state more errors pile up..
    if app.is_quitting:
        return

    window = find_active_window()
    if window is None:
        return

    # XXX: This does blocking IO and uses nested event loops... but it's simple
    dialog = ErrorDialog(window, error_text)
    while 1:
        response = dialog.run()
        if response == ErrorDialog.RESPONSE_QUIT:
            dialog.destroy()
            app.quit()
        elif response == ErrorDialog.RESPONSE_SUBMIT:
            dialog.hide()
            submit_dialog = SubmitErrorDialog(
                window, sentry_error.get_report())
            submit_response = submit_dialog.run()

            if submit_response == SubmitErrorDialog.RESPONSE_SUBMIT:
                sentry_error.set_comment(submit_dialog.get_comment())
                timeout_seconds = 5
                try:
                    sentry_error.send(timeout_seconds)
                except SentryError:
                    print_exc()
                submit_dialog.destroy()
                dialog.destroy()
            else:
                submit_dialog.destroy()
                dialog.show()
                continue
        else:
            dialog.destroy()
        break
Esempio n. 10
0
def run_error_dialogs(exc_info, sentry_error):
    error_text = u"%s: %s" % (
        exc_info[0].__name__,
        (text_type(exc_info[1]).strip() or u"\n").splitlines()[0])
    error_text += u"\n------\n"
    error_text += u"\n".join(format_exception(*exc_info))

    window = find_active_window()
    if window is None:
        return

    # XXX: This does blocking IO and uses nested event loops... but it's simple
    dialog = ErrorDialog(
        window, error_text, show_bug_report=(sentry_error is None))
    while 1:
        response = dialog.run()
        if response == ErrorDialog.RESPONSE_QUIT:
            dialog.destroy()
            app.quit()
        elif response == ErrorDialog.RESPONSE_SUBMIT:
            dialog.hide()
            submit_dialog = SubmitErrorDialog(
                window, sentry_error.get_report())
            submit_response = submit_dialog.run()

            if submit_response == SubmitErrorDialog.RESPONSE_SUBMIT:
                sentry_error.set_comment(submit_dialog.get_comment())
                timeout_seconds = 5
                try:
                    sentry_error.send(timeout_seconds)
                except SentryError:
                    print_exc()
                submit_dialog.destroy()
                dialog.destroy()
            else:
                submit_dialog.destroy()
                dialog.show()
                continue
        elif response == ErrorDialog.RESPONSE_BUGREPORT:
            url = get_github_issue_url(exc_info)
            website(url)
            dialog.destroy()
        else:
            dialog.destroy()
        break
Esempio n. 11
0
def main(argv=None):
    if argv is None:
        argv = sys_argv

    import quodlibet

    config_file = os.path.join(quodlibet.get_user_dir(), "config")
    quodlibet.init_cli(config_file=config_file)

    try:
        # we want basic commands not to import gtk (doubles process time)
        assert "gi.repository.Gtk" not in sys.modules
        sys.modules["gi.repository.Gtk"] = None
        startup_actions, cmds_todo = process_arguments(argv)
    finally:
        sys.modules.pop("gi.repository.Gtk", None)

    quodlibet.init()

    from quodlibet import app
    from quodlibet.qltk import add_signal_watch, Icons
    add_signal_watch(app.quit)

    import quodlibet.player
    import quodlibet.library
    from quodlibet import config
    from quodlibet import browsers
    from quodlibet import util

    app.name = "Quod Libet"
    app.id = "quodlibet"
    quodlibet.set_application_info(Icons.QUODLIBET, app.id, app.name)

    library_path = os.path.join(quodlibet.get_user_dir(), "songs")

    print_d("Initializing main library (%s)" % (
            quodlibet.util.path.unexpand(library_path)))

    library = quodlibet.library.init(library_path)
    app.library = library

    # this assumes that nullbe will always succeed
    from quodlibet.player import PlayerError
    wanted_backend = environ.get(
        "QUODLIBET_BACKEND", config.get("player", "backend"))

    try:
        player = quodlibet.player.init_player(wanted_backend, app.librarian)
    except PlayerError:
        print_exc()
        player = quodlibet.player.init_player("nullbe", app.librarian)

    app.player = player

    environ["PULSE_PROP_media.role"] = "music"
    environ["PULSE_PROP_application.icon_name"] = "quodlibet"

    browsers.init()

    from quodlibet.qltk.songlist import SongList, get_columns

    headers = get_columns()
    SongList.set_all_column_headers(headers)

    for opt in config.options("header_maps"):
        val = config.get("header_maps", opt)
        util.tags.add(opt, val)

    in_all = ("~filename ~uri ~#lastplayed ~#rating ~#playcount ~#skipcount "
              "~#added ~#bitrate ~current ~#laststarted ~basename "
              "~dirname").split()
    for Kind in browsers.browsers:
        if Kind.headers is not None:
            Kind.headers.extend(in_all)
        Kind.init(library)

    pm = quodlibet.init_plugins("no-plugins" in startup_actions)

    if hasattr(player, "init_plugins"):
        player.init_plugins()

    from quodlibet.qltk import unity
    unity.init("quodlibet.desktop", player)

    from quodlibet.qltk.songsmenu import SongsMenu
    SongsMenu.init_plugins()

    from quodlibet.util.cover import CoverManager
    app.cover_manager = CoverManager()
    app.cover_manager.init_plugins()

    from quodlibet.plugins.playlist import PLAYLIST_HANDLER
    PLAYLIST_HANDLER.init_plugins()

    from quodlibet.plugins.query import QUERY_HANDLER
    QUERY_HANDLER.init_plugins()

    from gi.repository import GLib

    def exec_commands(*args):
        for cmd in cmds_todo:
            try:
                resp = cmd_registry.run(app, *cmd)
            except CommandError:
                pass
            else:
                if resp is not None:
                    print_(resp, end="", flush=True)

    from quodlibet.qltk.quodlibetwindow import QuodLibetWindow, PlayerOptions
    # Call exec_commands after the window is restored, but make sure
    # it's after the mainloop has started so everything is set up.

    app.window = window = QuodLibetWindow(
        library, player,
        restore_cb=lambda:
            GLib.idle_add(exec_commands, priority=GLib.PRIORITY_HIGH))

    app.player_options = PlayerOptions(window)

    from quodlibet.qltk.window import Window

    from quodlibet.plugins.events import EventPluginHandler
    from quodlibet.plugins.gui import UserInterfacePluginHandler
    pm.register_handler(EventPluginHandler(library.librarian, player,
                                           app.window.songlist))
    pm.register_handler(UserInterfacePluginHandler())

    from quodlibet.mmkeys import MMKeysHandler
    from quodlibet.remote import Remote, RemoteError
    from quodlibet.commands import registry as cmd_registry, CommandError
    from quodlibet.qltk.tracker import SongTracker, FSInterface
    try:
        from quodlibet.qltk.dbus_ import DBusHandler
    except ImportError:
        DBusHandler = lambda player, library: None

    mmkeys_handler = MMKeysHandler(app)
    mmkeys_handler.start()

    current_path = os.path.join(quodlibet.get_user_dir(), "current")
    fsiface = FSInterface(current_path, player)
    remote = Remote(app, cmd_registry)
    try:
        remote.start()
    except RemoteError:
        exit_(1, True)

    DBusHandler(player, library)
    tracker = SongTracker(library.librarian, player, window.playlist)

    from quodlibet.qltk import session
    session.init("quodlibet")

    quodlibet.enable_periodic_save(save_library=True)

    if "start-playing" in startup_actions:
        player.paused = False

    if "start-hidden" in startup_actions:
        Window.prevent_inital_show(True)

    # restore browser windows
    from quodlibet.qltk.browser import LibraryBrowser
    GLib.idle_add(LibraryBrowser.restore, library, player,
                  priority=GLib.PRIORITY_HIGH)

    def before_quit():
        print_d("Saving active browser state")
        try:
            app.browser.save()
        except NotImplementedError:
            pass

        print_d("Shutting down player device %r." % player.version_info)
        player.destroy()

    quodlibet.run(window, before_quit=before_quit)

    app.player_options.destroy()
    quodlibet.finish_first_session(app.id)
    mmkeys_handler.quit()
    remote.stop()
    fsiface.destroy()

    tracker.destroy()
    quodlibet.library.save()

    config.save()

    print_d("Finished shutdown.")
Esempio n. 12
0
 def test_pass_exc_info(self):
     try:
         1 / 0
     except:
         with capture_output():
             print_exc(exc_info=sys.exc_info(), context="foo")
Esempio n. 13
0
 def test_main(self):
     try:
         1 / 0
     except:
         with capture_output():
             print_exc()
Esempio n. 14
0
 def do_fetch_versions():
     try:
         return fetch_versions(BUILD_TYPE)
     except UpdateError:
         print_exc()
         return None
Esempio n. 15
0
def main(argv=None):
    if argv is None:
        argv = sys_argv

    import quodlibet

    config_file = os.path.join(quodlibet.get_user_dir(), "config")
    quodlibet.init_cli(config_file=config_file)

    try:
        # we want basic commands not to import gtk (doubles process time)
        assert "gi.repository.Gtk" not in sys.modules
        sys.modules["gi.repository.Gtk"] = None
        startup_actions, cmds_todo = process_arguments(argv)
    finally:
        sys.modules.pop("gi.repository.Gtk", None)

    quodlibet.init()

    from quodlibet import app
    from quodlibet.qltk import add_signal_watch, Icons
    add_signal_watch(app.quit)

    import quodlibet.player
    import quodlibet.library
    from quodlibet import config
    from quodlibet import browsers
    from quodlibet import util

    app.name = "Quod Libet"
    app.id = "quodlibet"
    quodlibet.set_application_info(Icons.QUODLIBET, app.id, app.name)

    library_path = os.path.join(quodlibet.get_user_dir(), "songs")

    print_d("Initializing main library (%s)" % (
            quodlibet.util.path.unexpand(library_path)))

    library = quodlibet.library.init(library_path)
    app.library = library

    # this assumes that nullbe will always succeed
    from quodlibet.player import PlayerError
    wanted_backend = environ.get(
        "QUODLIBET_BACKEND", config.get("player", "backend"))

    try:
        player = quodlibet.player.init_player(wanted_backend, app.librarian)
    except PlayerError:
        print_exc()
        player = quodlibet.player.init_player("nullbe", app.librarian)

    app.player = player

    environ["PULSE_PROP_media.role"] = "music"
    environ["PULSE_PROP_application.icon_name"] = "quodlibet"

    browsers.init()

    from quodlibet.qltk.songlist import SongList, get_columns

    headers = get_columns()
    SongList.set_all_column_headers(headers)

    for opt in config.options("header_maps"):
        val = config.get("header_maps", opt)
        util.tags.add(opt, val)

    in_all = ("~filename ~uri ~#lastplayed ~#rating ~#playcount ~#skipcount "
              "~#added ~#bitrate ~current ~#laststarted ~basename "
              "~dirname").split()
    for Kind in browsers.browsers:
        if Kind.headers is not None:
            Kind.headers.extend(in_all)
        Kind.init(library)

    pm = quodlibet.init_plugins("no-plugins" in startup_actions)

    if hasattr(player, "init_plugins"):
        player.init_plugins()

    from quodlibet.qltk import unity
    unity.init("quodlibet.desktop", player)

    from quodlibet.qltk.songsmenu import SongsMenu
    SongsMenu.init_plugins()

    from quodlibet.util.cover import CoverManager
    app.cover_manager = CoverManager()
    app.cover_manager.init_plugins()

    from quodlibet.plugins.playlist import PLAYLIST_HANDLER
    PLAYLIST_HANDLER.init_plugins()

    from quodlibet.plugins.query import QUERY_HANDLER
    QUERY_HANDLER.init_plugins()

    from gi.repository import GLib

    def exec_commands(*args):
        for cmd in cmds_todo:
            try:
                resp = cmd_registry.run(app, *cmd)
            except CommandError:
                pass
            else:
                if resp is not None:
                    print_(resp, end="", flush=True)

    from quodlibet.qltk.quodlibetwindow import QuodLibetWindow, PlayerOptions
    # Call exec_commands after the window is restored, but make sure
    # it's after the mainloop has started so everything is set up.

    app.window = window = QuodLibetWindow(
        library, player,
        restore_cb=lambda:
            GLib.idle_add(exec_commands, priority=GLib.PRIORITY_HIGH))

    app.player_options = PlayerOptions(window)

    from quodlibet.qltk.window import Window

    from quodlibet.plugins.events import EventPluginHandler
    pm.register_handler(EventPluginHandler(library.librarian, player))

    from quodlibet.mmkeys import MMKeysHandler
    from quodlibet.remote import Remote, RemoteError
    from quodlibet.commands import registry as cmd_registry, CommandError
    from quodlibet.qltk.tracker import SongTracker, FSInterface
    try:
        from quodlibet.qltk.dbus_ import DBusHandler
    except ImportError:
        DBusHandler = lambda player, library: None

    mmkeys_handler = MMKeysHandler(app)
    mmkeys_handler.start()

    current_path = os.path.join(quodlibet.get_user_dir(), "current")
    fsiface = FSInterface(current_path, player)
    remote = Remote(app, cmd_registry)
    try:
        remote.start()
    except RemoteError:
        exit_(1, True)

    DBusHandler(player, library)
    tracker = SongTracker(library.librarian, player, window.playlist)

    from quodlibet.qltk import session
    session.init("quodlibet")

    quodlibet.enable_periodic_save(save_library=True)

    if "start-playing" in startup_actions:
        player.paused = False

    if "start-hidden" in startup_actions:
        Window.prevent_inital_show(True)

    # restore browser windows
    from quodlibet.qltk.browser import LibraryBrowser
    GLib.idle_add(LibraryBrowser.restore, library, player,
                  priority=GLib.PRIORITY_HIGH)

    def before_quit():
        print_d("Saving active browser state")
        try:
            app.browser.save()
        except NotImplementedError:
            pass

        print_d("Shutting down player device %r." % player.version_info)
        player.destroy()

    quodlibet.run(window, before_quit=before_quit)

    app.player_options.destroy()
    quodlibet.finish_first_session(app.id)
    mmkeys_handler.quit()
    remote.stop()
    fsiface.destroy()

    tracker.destroy()
    quodlibet.library.save()

    config.save()

    print_d("Finished shutdown.")
Esempio n. 16
0
 def test_no_stack(self):
     with capture_output():
         print_exc((None, None, None))
Esempio n. 17
0
 def do_fetch_versions():
     try:
         return fetch_versions(BUILD_TYPE)
     except UpdateError:
         print_exc()
         return None
Esempio n. 18
0
 def test_main(self):
     try:
         1 / 0
     except:
         with capture_output():
             print_exc()
Esempio n. 19
0
 def test_pass_exc_info(self):
     try:
         1 / 0
     except:
         with capture_output():
             print_exc(exc_info=sys.exc_info(), context="foo")
Esempio n. 20
0
 def test_no_stack(self):
     with capture_output():
         print_exc((None, None, None))