Cache HTML/JS resource files when starting
This mostly reverts 9edc5a665e
(see #1362).
Fixes #1943
This commit is contained in:
parent
78623f4ec8
commit
b4a2352833
@ -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
|
||||
~~~~~~~
|
||||
|
@ -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)
|
||||
|
@ -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>
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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():
|
||||
|
@ -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'),
|
||||
|
Loading…
Reference in New Issue
Block a user