From f3db2c3fbef908572d4647346388b0f33d8d88e2 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Mon, 17 Jun 2019 13:21:58 +0200 Subject: Nuke the cache when the Qt version changed https://bugreports.qt.io/browse/QTBUG-72532 --- qutebrowser/config/configfiles.py | 17 +++++++-- qutebrowser/misc/backendproblem.py | 30 ++++++++++++++-- tests/unit/config/test_configfiles.py | 68 +++++++++++++++++++++++++++++++---- 3 files changed, 105 insertions(+), 10 deletions(-) diff --git a/qutebrowser/config/configfiles.py b/qutebrowser/config/configfiles.py index 0d1dcb22f..402bfcf03 100644 --- a/qutebrowser/config/configfiles.py +++ b/qutebrowser/config/configfiles.py @@ -30,7 +30,7 @@ import contextlib import typing import yaml -from PyQt5.QtCore import pyqtSignal, QObject, QSettings +from PyQt5.QtCore import pyqtSignal, QObject, QSettings, qVersion import qutebrowser from qutebrowser.config import configexc, config, configdata, configutils @@ -55,6 +55,17 @@ class StateConfig(configparser.ConfigParser): super().__init__() self._filename = os.path.join(standarddir.data(), 'state') self.read(self._filename, encoding='utf-8') + + qt_version = qVersion() + # We handle this here, so we can avoid setting qt_version_changed if + # the config is brand new, but can still set it when qt_version wasn't + # there before... + if 'general' in self: + old_qt_version = self['general'].get('qt_version', None) + self.qt_version_changed = old_qt_version != qt_version + else: + self.qt_version_changed = False + for sect in ['general', 'geometry']: try: self.add_section(sect) @@ -65,6 +76,9 @@ class StateConfig(configparser.ConfigParser): for key in deleted_keys: self['general'].pop(key, None) + self['general']['qt_version'] = qt_version + self['general']['version'] = qutebrowser.__version__ + def init_save_manager(self, save_manager: 'savemanager.SaveManager') -> None: """Make sure the config gets saved properly. @@ -638,7 +652,6 @@ def init() -> None: """Initialize config storage not related to the main config.""" global state state = StateConfig() - state['general']['version'] = qutebrowser.__version__ # Set the QSettings path to something like # ~/.config/qutebrowser/qsettings/qutebrowser/qutebrowser.conf so it diff --git a/qutebrowser/misc/backendproblem.py b/qutebrowser/misc/backendproblem.py index da9392f3d..796d97fea 100644 --- a/qutebrowser/misc/backendproblem.py +++ b/qutebrowser/misc/backendproblem.py @@ -26,6 +26,7 @@ import html import ctypes import ctypes.util import enum +import shutil import attr from PyQt5.QtCore import Qt @@ -33,8 +34,9 @@ from PyQt5.QtWidgets import (QApplication, QDialog, QPushButton, QHBoxLayout, QVBoxLayout, QLabel, QMessageBox) from PyQt5.QtNetwork import QSslSocket -from qutebrowser.config import config -from qutebrowser.utils import usertypes, objreg, version, qtutils, log, utils +from qutebrowser.config import config, configfiles +from qutebrowser.utils import (usertypes, objreg, version, qtutils, log, utils, + standarddir) from qutebrowser.misc import objects, msgbox @@ -397,6 +399,29 @@ def _check_backend_modules(): raise utils.Unreachable +def _handle_cache_nuking(): + """Nuke the QtWebEngine cache if the Qt version changed. + + WORKAROUND for https://bugreports.qt.io/browse/QTBUG-72532 + """ + if not configfiles.state.qt_version_changed: + return + + # Only nuke the cache in cases where we know there are problems. + # It seems these issues started with Qt 5.12. + # They should be fixed with Qt 5.12.5: + # https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/265408 + affected = (qtutils.version_check('5.12', compiled=False) and not + qtutils.version_check('5.12.5', compiled=False)) + if not affected: + return + + log.init.info("Qt version changed, nuking QtWebEngine cache") + cache_dir = os.path.join(standarddir.cache(), 'webengine') + if os.path.exists(cache_dir): + shutil.rmtree(cache_dir) + + def init(): """Check for various issues related to QtWebKit/QtWebEngine.""" _check_backend_modules() @@ -405,6 +430,7 @@ def init(): _handle_wayland() _nvidia_shader_workaround() _handle_nouveau_graphics() + _handle_cache_nuking() else: assert objects.backend == usertypes.Backend.QtWebKit, objects.backend _handle_ssl_support(fatal=True) diff --git a/tests/unit/config/test_configfiles.py b/tests/unit/config/test_configfiles.py index 9609cdafa..e7b830d93 100644 --- a/tests/unit/config/test_configfiles.py +++ b/tests/unit/config/test_configfiles.py @@ -76,14 +76,48 @@ def autoconfig(config_tmpdir): @pytest.mark.parametrize('old_data, insert, new_data', [ - (None, False, '[general]\n\n[geometry]\n\n'), - ('[general]\nfooled = true', False, '[general]\n\n[geometry]\n\n'), - ('[general]\nfoobar = 42', False, - '[general]\nfoobar = 42\n\n[geometry]\n\n'), - (None, True, '[general]\nnewval = 23\n\n[geometry]\n\n'), + (None, + False, + '[general]\n' + 'qt_version = 5.6.7\n' + 'version = 1.2.3\n' + '\n' + '[geometry]\n' + '\n'), + ('[general]\n' + 'fooled = true', + False, + '[general]\n' + 'qt_version = 5.6.7\n' + 'version = 1.2.3\n' + '\n' + '[geometry]\n' + '\n'), + ('[general]\n' + 'foobar = 42', + False, + '[general]\n' + 'foobar = 42\n' + 'qt_version = 5.6.7\n' + 'version = 1.2.3\n' + '\n' + '[geometry]\n' + '\n'), + (None, + True, + '[general]\n' + 'qt_version = 5.6.7\n' + 'version = 1.2.3\n' + 'newval = 23\n' + '\n' + '[geometry]\n' + '\n'), ]) -def test_state_config(fake_save_manager, data_tmpdir, +def test_state_config(fake_save_manager, data_tmpdir, monkeypatch, old_data, insert, new_data): + monkeypatch.setattr(configfiles.qutebrowser, '__version__', '1.2.3') + monkeypatch.setattr(configfiles, 'qVersion', lambda: '5.6.7') + statefile = data_tmpdir / 'state' if old_data is not None: statefile.write_text(old_data, 'utf-8') @@ -102,6 +136,28 @@ def test_state_config(fake_save_manager, data_tmpdir, fake_save_manager.add_saveable('state-config', unittest.mock.ANY) +@pytest.mark.parametrize('old_version, new_version, changed', [ + (None, '5.12.1', False), + ('5.12.1', '5.12.1', False), + ('5.12.2', '5.12.1', True), + ('5.12.1', '5.12.2', True), + ('5.13.0', '5.12.2', True), + ('5.12.2', '5.13.0', True), +]) +def test_qt_version_changed(data_tmpdir, monkeypatch, + old_version, new_version, changed): + monkeypatch.setattr(configfiles, 'qVersion', lambda: new_version) + + statefile = data_tmpdir / 'state' + if old_version is not None: + data = ('[general]\n' + 'qt_version = {}'.format(old_version)) + statefile.write_text(data, 'utf-8') + + state = configfiles.StateConfig() + assert state.qt_version_changed == changed + + class TestYaml: pytestmark = pytest.mark.usefixtures('config_tmpdir') -- cgit v1.2.3-54-g00ecf