summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Bruhin <git@the-compiler.org>2018-03-05 09:03:58 +0100
committerFlorian Bruhin <git@the-compiler.org>2018-03-05 09:08:06 +0100
commitb4a2352833bfb06c86c1afb8b088cead0ef7c6d5 (patch)
treefc6a7286288670470242e12e349296028eba3688
parent78623f4ec8f9fc98a90ace5efe581bac7262d52a (diff)
downloadqutebrowser-b4a2352833bfb06c86c1afb8b088cead0ef7c6d5.tar.gz
qutebrowser-b4a2352833bfb06c86c1afb8b088cead0ef7c6d5.zip
Cache HTML/JS resource files when starting
This mostly reverts 9edc5a665e414ae2ec8f5bc04a99bce2bc4e6d33 (see #1362). Fixes #1943
-rw-r--r--doc/changelog.asciidoc2
-rw-r--r--qutebrowser/app.py1
-rw-r--r--qutebrowser/html/undef_error.html22
-rw-r--r--qutebrowser/utils/jinja.py11
-rw-r--r--qutebrowser/utils/utils.py14
-rw-r--r--tests/unit/utils/test_jinja.py17
-rw-r--r--tests/unit/utils/test_utils.py8
7 files changed, 30 insertions, 45 deletions
diff --git a/doc/changelog.asciidoc b/doc/changelog.asciidoc
index ffbf9ebfc..d30eb3ca8 100644
--- a/doc/changelog.asciidoc
+++ b/doc/changelog.asciidoc
@@ -117,6 +117,8 @@ Fixed
- Crash when opening an invalid URL from an application on macOS.
- Crash with an empty `completion.timestamp_format`.
- Crash when `completion.min_chars` is set in some cases.
+- HTML/JS resource files are now read into RAM on start to avoid crashes when
+ changing qutebrowser versions while it's open.
Removed
~~~~~~~
diff --git a/qutebrowser/app.py b/qutebrowser/app.py
index e9f9d2229..014e02c5f 100644
--- a/qutebrowser/app.py
+++ b/qutebrowser/app.py
@@ -95,6 +95,7 @@ def run(args):
log.init.debug("Initializing directories...")
standarddir.init(args)
+ utils.preload_resources()
log.init.debug("Initializing config...")
configinit.early_init(args)
diff --git a/qutebrowser/html/undef_error.html b/qutebrowser/html/undef_error.html
deleted file mode 100644
index 55a47ca95..000000000
--- a/qutebrowser/html/undef_error.html
+++ /dev/null
@@ -1,22 +0,0 @@
-<!DOCTYPE html>
-<!--
-vim: ft=html fileencoding=utf-8 sts=4 sw=4 et:
--->
-
-<html>
- <head>
- <meta charset="utf-8">
- <title>Error while rendering HTML</title>
- </head>
- <body>
- <h1>Error while rendering internal qutebrowser page</h1>
- <p>There was an error while rendering {pagename}.</p>
-
- <p>This most likely happened because you updated qutebrowser but didn't restart yet.</p>
-
- <p>If you believe this isn't the case and this is a bug, please do :report.<p>
-
- <h2>Traceback</h2>
- <pre>{traceback}</pre>
- </body>
-</html>
diff --git a/qutebrowser/utils/jinja.py b/qutebrowser/utils/jinja.py
index d4ce3368f..b06444f93 100644
--- a/qutebrowser/utils/jinja.py
+++ b/qutebrowser/utils/jinja.py
@@ -22,12 +22,10 @@
import os
import os.path
import contextlib
-import traceback
import mimetypes
import html
import jinja2
-import jinja2.exceptions
from PyQt5.QtCore import QUrl
from qutebrowser.utils import utils, urlutils, log
@@ -125,14 +123,7 @@ class Environment(jinja2.Environment):
def render(template, **kwargs):
"""Render the given template and pass the given arguments to it."""
- try:
- return environment.get_template(template).render(**kwargs)
- except jinja2.exceptions.UndefinedError:
- log.misc.exception("UndefinedError while rendering " + template)
- err_path = os.path.join('html', 'undef_error.html')
- err_template = utils.read_file(err_path)
- tb = traceback.format_exc()
- return err_template.format(pagename=template, traceback=tb)
+ return environment.get_template(template).render(**kwargs)
environment = Environment()
diff --git a/qutebrowser/utils/utils.py b/qutebrowser/utils/utils.py
index f03d42844..9f3acde5a 100644
--- a/qutebrowser/utils/utils.py
+++ b/qutebrowser/utils/utils.py
@@ -32,6 +32,7 @@ import functools
import contextlib
import socket
import shlex
+import glob
from PyQt5.QtCore import QUrl
from PyQt5.QtGui import QColor, QClipboard, QDesktopServices
@@ -51,6 +52,7 @@ from qutebrowser.utils import qtutils, log
fake_clipboard = None
log_clipboard = False
+_resource_cache = {}
is_mac = sys.platform.startswith('darwin')
is_linux = sys.platform.startswith('linux')
@@ -140,6 +142,15 @@ def compact_text(text, elidelength=None):
return out
+def preload_resources():
+ """Load resource files into the cache."""
+ for subdir, pattern in [('html', '*.html'), ('javascript', '*.js')]:
+ path = resource_filename(subdir)
+ for full_path in glob.glob(os.path.join(path, pattern)):
+ sub_path = os.path.join(subdir, os.path.basename(full_path))
+ _resource_cache[sub_path] = read_file(sub_path)
+
+
def read_file(filename, binary=False):
"""Get the contents of a file contained with qutebrowser.
@@ -151,6 +162,9 @@ def read_file(filename, binary=False):
Return:
The file contents as string.
"""
+ if not binary and filename in _resource_cache:
+ return _resource_cache[filename]
+
if hasattr(sys, 'frozen'):
# PyInstaller doesn't support pkg_resources :(
# https://github.com/pyinstaller/pyinstaller/wiki/FAQ#misc
diff --git a/tests/unit/utils/test_jinja.py b/tests/unit/utils/test_jinja.py
index f47155f91..b1a50772e 100644
--- a/tests/unit/utils/test_jinja.py
+++ b/tests/unit/utils/test_jinja.py
@@ -23,6 +23,7 @@ import os
import os.path
import logging
+import jinja2.exceptions
import pytest
from PyQt5.QtCore import QUrl
@@ -32,7 +33,6 @@ from qutebrowser.utils import utils, jinja
@pytest.fixture(autouse=True)
def patch_read_file(monkeypatch):
"""pytest fixture to patch utils.read_file."""
- real_read_file = utils.read_file
real_resource_filename = utils.resource_filename
def _read_file(path, binary=False):
@@ -52,9 +52,6 @@ def patch_read_file(monkeypatch):
elif path == os.path.join('html', 'undef.html'):
assert not binary
return """{{ does_not_exist() }}"""
- elif path == os.path.join('html', 'undef_error.html'):
- assert not binary
- return real_read_file(path)
elif path == os.path.join('html', 'attributeerror.html'):
assert not binary
return """{{ obj.foobar }}"""
@@ -129,15 +126,9 @@ def test_utf8():
def test_undefined_function(caplog):
- """Make sure we don't crash if an undefined function is called."""
- with caplog.at_level(logging.ERROR):
- data = jinja.render('undef.html')
- assert 'There was an error while rendering undef.html' in data
- assert "'does_not_exist' is undefined" in data
- assert data.startswith('<!DOCTYPE html>')
-
- assert len(caplog.records) == 1
- assert caplog.records[0].msg == "UndefinedError while rendering undef.html"
+ """Make sure undefined attributes crash since we preload resources.."""
+ with pytest.raises(jinja2.exceptions.UndefinedError):
+ jinja.render('undef.html')
def test_attribute_error():
diff --git a/tests/unit/utils/test_utils.py b/tests/unit/utils/test_utils.py
index b2eef0237..df0eb9ecb 100644
--- a/tests/unit/utils/test_utils.py
+++ b/tests/unit/utils/test_utils.py
@@ -133,6 +133,14 @@ class TestReadFile:
content = utils.read_file(os.path.join('utils', 'testfile'))
assert content.splitlines()[0] == "Hello World!"
+ @pytest.mark.parametrize('filename', ['javascript/scroll.js',
+ 'html/error.html'])
+ def test_read_cached_file(self, mocker, filename):
+ utils.preload_resources()
+ m = mocker.patch('pkg_resources.resource_string')
+ utils.read_file(filename)
+ m.assert_not_called()
+
def test_readfile_binary(self):
"""Read a test file in binary mode."""
content = utils.read_file(os.path.join('utils', 'testfile'),