From fc7961ae2247cdca28995fe45d33022237c2f7d8 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 15 Nov 2016 10:33:49 +0100 Subject: [PATCH] Set correct paths for QtWebEngine --- .../browser/webengine/webenginesettings.py | 13 +-- qutebrowser/utils/standarddir.py | 49 +++++++++ tests/unit/utils/test_standarddir.py | 99 +++++++++++++++++++ 3 files changed, 155 insertions(+), 6 deletions(-) diff --git a/qutebrowser/browser/webengine/webenginesettings.py b/qutebrowser/browser/webengine/webenginesettings.py index 3eca8cd2c..7b38f47fc 100644 --- a/qutebrowser/browser/webengine/webenginesettings.py +++ b/qutebrowser/browser/webengine/webenginesettings.py @@ -27,11 +27,11 @@ Module attributes: import os # pylint: disable=no-name-in-module,import-error,useless-suppression -from PyQt5.QtWebEngineWidgets import QWebEngineSettings +from PyQt5.QtWebEngineWidgets import QWebEngineSettings, QWebEngineProfile # pylint: enable=no-name-in-module,import-error,useless-suppression from qutebrowser.config import websettings, config -from qutebrowser.utils import objreg, utils +from qutebrowser.utils import objreg, utils, standarddir class Attribute(websettings.Attribute): @@ -70,12 +70,15 @@ def update_settings(section, option): def init(): """Initialize the global QWebSettings.""" - # FIXME:qtwebengine set paths in profile - if config.get('general', 'developer-extras'): # FIXME:qtwebengine Make sure we call globalSettings *after* this... os.environ['QTWEBENGINE_REMOTE_DEBUGGING'] = str(utils.random_port()) + profile = QWebEngineProfile.defaultProfile() + profile.setCachePath(os.path.join(standarddir.cache(), 'webengine')) + profile.setPersistentStoragePath( + os.path.join(standarddir.data(), 'webengine')) + websettings.init_mappings(MAPPINGS) objreg.get('config').changed.connect(update_settings) @@ -98,13 +101,11 @@ def shutdown(): # - PictographFont # # TODO settings on profile: -# - cachePath # - httpAcceptLanguage # - httpCacheMaximumSize # - httpUserAgent # - persistentCookiesPolicy # - offTheRecord -# - persistentStoragePath # # TODO settings elsewhere: # - proxy diff --git a/qutebrowser/utils/standarddir.py b/qutebrowser/utils/standarddir.py index bd80cd9af..05fe7ce27 100644 --- a/qutebrowser/utils/standarddir.py +++ b/qutebrowser/utils/standarddir.py @@ -21,6 +21,7 @@ import os import sys +import shutil import os.path from PyQt5.QtCore import QCoreApplication, QStandardPaths @@ -188,6 +189,8 @@ def init(args): log.init.debug("Base directory: {}".format(args.basedir)) _args = args _init_cachedir_tag() + if args is not None: + _move_webengine_data() def _init_cachedir_tag(): @@ -207,3 +210,49 @@ def _init_cachedir_tag(): "cachedir/\n") except OSError: log.init.exception("Failed to create CACHEDIR.TAG") + + +def _move_webengine_data(): + """Move QtWebEngine data from an older location to the new one.""" + # Do NOT use _writable_location here as that'd give us a wrong path + old_data_dir = QStandardPaths.writableLocation(QStandardPaths.DataLocation) + old_cache_dir = QStandardPaths.writableLocation( + QStandardPaths.CacheLocation) + new_data_dir = os.path.join(data(), 'webengine') + new_cache_dir = os.path.join(cache(), 'webengine') + + if (not os.path.exists(os.path.join(old_data_dir, 'QtWebEngine')) and + not os.path.exists(os.path.join(old_cache_dir, 'QtWebEngine'))): + return + + log.init.debug("Moving QtWebEngine data from {} to {}".format( + old_data_dir, new_data_dir)) + log.init.debug("Moving QtWebEngine cache from {} to {}".format( + old_cache_dir, new_cache_dir)) + + if os.path.exists(new_data_dir): + log.init.warning("Failed to move old QtWebEngine data as {} already " + "exists!".format(new_data_dir)) + return + if os.path.exists(new_cache_dir): + log.init.warning("Failed to move old QtWebEngine cache as {} already " + "exists!".format(new_cache_dir)) + return + + try: + shutil.move(os.path.join(old_data_dir, 'QtWebEngine', 'Default'), + new_data_dir) + shutil.move(os.path.join(old_cache_dir, 'QtWebEngine', 'Default'), + new_cache_dir) + + # Remove e.g. + # ~/.local/share/qutebrowser/qutebrowser/QtWebEngine/Default + if old_data_dir.split(os.sep)[-2:] == ['qutebrowser', 'qutebrowser']: + log.init.debug("Removing {} / {}".format( + old_data_dir, old_cache_dir)) + for old_dir in old_data_dir, old_cache_dir: + os.rmdir(os.path.join(old_dir, 'QtWebEngine')) + os.rmdir(old_dir) + except OSError as e: + log.init.exception("Failed to move old QtWebEngine data/cache: " + "{}".format(e)) diff --git a/tests/unit/utils/test_standarddir.py b/tests/unit/utils/test_standarddir.py index de87509ba..eb348132b 100644 --- a/tests/unit/utils/test_standarddir.py +++ b/tests/unit/utils/test_standarddir.py @@ -300,3 +300,102 @@ class TestSystemData: standarddir.init(fake_args) monkeypatch.setattr('sys.platform', "potato") assert standarddir.system_data() == standarddir.data() + + +class TestMoveWebEngineData: + + """Test moving QtWebEngine data from an old location.""" + + @pytest.fixture(autouse=True) + def patch_standardpaths(self, tmpdir, monkeypatch): + locations = { + QStandardPaths.DataLocation: str(tmpdir / 'data'), + QStandardPaths.CacheLocation: str(tmpdir / 'cache'), + } + monkeypatch.setattr(standarddir.QStandardPaths, 'writableLocation', + locations.get) + monkeypatch.setattr(standarddir, 'data', + lambda: str(tmpdir / 'new_data')) + monkeypatch.setattr(standarddir, 'cache', + lambda: str(tmpdir / 'new_cache')) + + @pytest.fixture + def files(self, tmpdir): + files = collections.namedtuple('Files', ['old_data', 'new_data', + 'old_cache', 'new_cache']) + return files( + old_data=tmpdir / 'data' / 'QtWebEngine' / 'Default' / 'datafile', + new_data=tmpdir / 'new_data' / 'webengine' / 'datafile', + old_cache=(tmpdir / 'cache' / 'QtWebEngine' / 'Default' / + 'cachefile'), + new_cache=(tmpdir / 'new_cache' / 'webengine' / 'cachefile'), + ) + + def test_no_webengine_dir(self, caplog): + """Nothing should happen without any QtWebEngine directory.""" + standarddir._move_webengine_data() + assert not any(rec.message.startswith('Moving QtWebEngine') + for rec in caplog.records) + + def test_moving_data(self, files): + files.old_data.ensure() + files.old_cache.ensure() + + standarddir._move_webengine_data() + + assert not files.old_data.exists() + assert not files.old_cache.exists() + assert files.new_data.exists() + assert files.new_cache.exists() + + @pytest.mark.parametrize('what', ['data', 'cache']) + def test_already_existing(self, files, caplog, what): + files.old_data.ensure() + files.old_cache.ensure() + + if what == 'data': + files.new_data.ensure() + else: + files.new_cache.ensure() + + with caplog.at_level(logging.WARNING): + standarddir._move_webengine_data() + + record = caplog.records[-1] + expected = "Failed to move old QtWebEngine {}".format(what) + assert record.message.startswith(expected) + + def test_deleting_empty_dirs(self, monkeypatch, tmpdir): + """When we have a qutebrowser/qutebrowser subfolder, clean it up.""" + old_data = tmpdir / 'data' / 'qutebrowser' / 'qutebrowser' + old_cache = tmpdir / 'cache' / 'qutebrowser' / 'qutebrowser' + locations = { + QStandardPaths.DataLocation: str(old_data), + QStandardPaths.CacheLocation: str(old_cache), + } + monkeypatch.setattr(standarddir.QStandardPaths, 'writableLocation', + locations.get) + + old_data_file = old_data / 'QtWebEngine' / 'Default' / 'datafile' + old_cache_file = old_cache / 'QtWebEngine' / 'Default' / 'cachefile' + old_data_file.ensure() + old_cache_file.ensure() + + standarddir._move_webengine_data() + + assert not (tmpdir / 'data' / 'qutebrowser' / 'qutebrowser').exists() + assert not (tmpdir / 'cache' / 'qutebrowser' / 'qutebrowser').exists() + + def test_deleting_error(self, files, monkeypatch, mocker, caplog): + """When there was an error it should be logged.""" + mock = mocker.Mock(side_effect=OSError('error')) + monkeypatch.setattr(standarddir.shutil, 'move', mock) + files.old_data.ensure() + files.old_cache.ensure() + + with caplog.at_level(logging.ERROR): + standarddir._move_webengine_data() + + record = caplog.records[-1] + expected = "Failed to move old QtWebEngine data/cache: error" + assert record.message == expected