Compare commits

...

26 Commits
nsis ... v0.8.2

Author SHA1 Message Date
Florian Bruhin
113675a0b5 Release v0.8.2 2016-08-02 18:33:59 +02:00
Florian Bruhin
c4d8a767f9 Update changelog for 0.8.2 2016-08-02 18:33:36 +02:00
Florian Bruhin
de3867fe95 Bump up filename length limit to 50
The usual limit seems to be 255 bytes, so even when assuming 5-byte
UTF-8 chars for every letter, 50 should be fine.

http://serverfault.com/questions/9546/filename-length-limits-on-linux/9548#9548
2016-08-02 16:17:05 +02:00
Daniel Schadt
6ac3940264 open-download: don't crash on download cancel
Fixes #1728.
2016-08-02 16:17:05 +02:00
Daniel Schadt
5e9eafd5a3 open-download: force encoding for filename
Fixes #1726.
2016-08-02 16:17:05 +02:00
Daniel Schadt
5d4b9e815c open-download: make sure the name is not too long
Fixes #1725.

Make sure that the temporary filename is not too long by restricting the
suggested part to 20 characters.
2016-08-02 16:17:05 +02:00
Daniel Schadt
3eba7fc314 downloads: don't crash on OSError in open-download
Fixes the crash in #1725, but does not provide a solution. The browser
won't crash, but the file won't be downloaded and opened either.
2016-08-02 16:17:05 +02:00
Florian Bruhin
11d7486f97 freeze.py: Copy plugin folders on Windows
This makes HTML5 video work.
Fixes #1068.
2016-08-02 15:56:40 +02:00
Florian Bruhin
8e7a1d3d97 Use HTML content for localstorage test
JS logging is disabled by QtWebKit in private browsing mode
2016-08-02 15:18:58 +02:00
Florian Bruhin
98704c0471 Fix deleting of quickmarks with ctrl-d 2016-08-02 14:58:12 +02:00
Florian Bruhin
c2bf595b79 Don't use QSignalSpy in IPC test
Fixes #1727.

For another testcase in the same file we still need to use it until
pytest-qt has a MultiSignalBlocker.args.
2016-08-02 14:26:11 +02:00
Florian Bruhin
f73f3a2001 Tunnel private-browsing to QtWebKit correctly 2016-08-02 14:24:34 +02:00
Florian Bruhin
afde5bbc79 Fix using a relative path with --basedir 2016-08-02 14:23:38 +02:00
Florian Bruhin
66a76a4504 travis: Remove testing on Ubuntu Wily 2016-08-02 11:20:12 +02:00
Florian Bruhin
feb73f06c5 Fix ;o/;O default bindings 2016-08-02 10:52:45 +02:00
Florian Bruhin
e32fbe9013 QtWebEngine: Fix crash when closing/reopening tabs 2016-08-02 10:52:24 +02:00
Florian Bruhin
776a16bf65 Fix crash when opening http://foo%40bar@baz 2016-08-02 10:51:54 +02:00
Florian Bruhin
225c860452 Fix <input /> test in test_webelem 2016-08-02 10:48:18 +02:00
Florian Bruhin
f982402526 Consider input elements without type for hinting 2016-08-02 10:46:23 +02:00
Florian Bruhin
6a6e7ecb38 travis: Switch bot to #qutebrowser-dev 2016-07-27 13:05:09 +02:00
Florian Bruhin
c94ed93f13 build_release: Fix call_tox with no python on Win 2016-07-27 12:36:43 +02:00
Florian Bruhin
95d1721f01 Release v0.8.1 2016-07-27 12:31:30 +02:00
Florian Bruhin
410be07f54 Hide harfbuzz warning if frozen 2016-07-27 12:15:37 +02:00
Florian Bruhin
01de52c23a Improve error message on OS X without QtWebEngine 2016-07-27 12:13:45 +02:00
Florian Bruhin
a84807ed05 Handle empty command in CommandRunner.parse_all
Sicne we now call self._get_alias there, we also need to make sure it's
not an empty string before that.

Introduced in #1577. Fixes #1690.
2016-07-27 11:23:30 +02:00
Florian Bruhin
2795ae9478 Update build scripts from master 2016-07-26 17:01:08 +02:00
27 changed files with 223 additions and 86 deletions

View File

@@ -12,9 +12,6 @@ matrix:
- os: linux
env: DOCKER=archlinux
services: docker
- os: linux
env: DOCKER=ubuntu-wily
services: docker
- os: linux
env: DOCKER=ubuntu-xenial
services: docker
@@ -63,8 +60,8 @@ notifications:
- https://buildtimetrend.herokuapp.com/travis
irc:
channels:
- "chat.freenode.net#qutebrowser"
on_success: change
- "chat.freenode.net#qutebrowser-dev"
on_success: always
on_failure: always
skip_join: true
template:

View File

@@ -14,6 +14,41 @@ This project adheres to http://semver.org/[Semantic Versioning].
// `Fixed` for any bug fixes.
// `Security` to invite users to upgrade in case of vulnerabilities.
v0.8.2
------
Fixed
~~~~~
- Fixed `general -> private-browsing` not being set correctly until a restart
(which caused e.g. local storage to be enabled).
- Fixed crash when using hints with JS disabled in some rare circumstances.
- When hinting input fields (`:t`), also consider input elements without a type.
- Fixed crash when opening an invalid URL with a percent-encoded and a real @ in it
- Fixed default `;o` and `;O` bindings
- Fixed local storage not working (and possible other bugs) when using a
relative path with `--basedir`.
- Fixed crash when deleting a quickmark with Ctrl-D
- Fixed HTML5 video playback on Windows
- Fixed crash when using `:prompt-open-download` with a file with chars not
encodable with the OS' filesystem encoding (e.g. with `LC_ALL=C`)
- Fixed `:prompt-open-download` with a too long filename (< 255 bytes)
- Fixed crash when cancelling a download after doing `:prompt-open-download`
- Fixed crash when writing a download to disk fails with
`:prompt-open-download`.
- Fixed HTML5 video playback on Windows
v0.8.1
------
Fixed
~~~~~
- Fix crash when pressing enter without a command
- Adjust error message to point out QtWebEngine is unsupported with the OS
X .app currently.
- Hide Harfbuzz warning with the OS X .app
v0.8.0
------
@@ -33,7 +68,7 @@ Added
`$QUTE_DOWNLOAD_DIR` available for userscripts.
- New option `ui` -> `status-position` to configure the position of the
status bar (top/bottom).
- New `--pdf <filename>` argument for `:print` which can be used to generate a
- New `--pdf <filename>` argument for `:print` WHICH can be used to generate a
PDF without a dialog.
Changed

View File

@@ -1,37 +0,0 @@
FROM ubuntu:wily
MAINTAINER Florian Bruhin <me@the-compiler.org>
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get -y update && \
apt-get -y dist-upgrade && \
apt-get -y install --no-install-recommends \
python3-pyqt5 \
python3-pyqt5.qtwebkit \
python-tox \
python3-sip \
xvfb \
git \
python3-setuptools \
wget \
herbstluftwm \
language-pack-en \
libjs-pdf \
dbus
RUN dbus-uuidgen --ensure
RUN useradd user && mkdir /home/user && chown -R user:users /home/user
USER user
WORKDIR /home/user
ENV DISPLAY=:0
ENV LC_ALL=en_US.UTF-8
ENV LANG=en_US.UTF-8
CMD Xvfb -screen 0 800x600x24 :0 & \
sleep 2 && \
herbstluftwm & \
git clone /outside qutebrowser.git && \
cd qutebrowser.git && \
tox -e py34

View File

@@ -28,7 +28,7 @@ __copyright__ = "Copyright 2014-2016 Florian Bruhin (The Compiler)"
__license__ = "GPL"
__maintainer__ = __author__
__email__ = "mail@qutebrowser.org"
__version_info__ = (0, 8, 0)
__version_info__ = (0, 8, 2)
__version__ = '.'.join(str(e) for e in __version_info__)
__description__ = "A keyboard-driven, vim-like browser based on PyQt5 and QtWebKit."

View File

@@ -211,7 +211,11 @@ class WebEngineScroller(browsertab.AbstractScroller):
"""Update the scroll position attributes when it changed."""
def update_scroll_pos(jsret):
"""Callback after getting scroll position via JS."""
assert isinstance(jsret, dict)
if jsret is None:
# This can happen when the callback would get called after
# shutting down a tab
return
assert isinstance(jsret, dict), jsret
self._pos_perc = (jsret['perc']['x'], jsret['perc']['y'])
self._pos_px = QPoint(jsret['px']['x'], jsret['px']['y'])
self.perc_changed.emit(*self._pos_perc)

View File

@@ -947,13 +947,28 @@ class DownloadManager(QAbstractListModel):
download.set_filename(target.filename)
elif isinstance(target, usertypes.OpenFileDownloadTarget):
tmp_manager = objreg.get('temporary-downloads')
fobj = tmp_manager.get_tmpfile(suggested_filename)
download.finished.connect(download.open_file)
try:
fobj = tmp_manager.get_tmpfile(suggested_filename)
except OSError as exc:
msg = "Download error: {}".format(exc)
message.error(self._win_id, msg)
download.cancel()
return
download.finished.connect(
functools.partial(self._open_download, download))
download.autoclose = True
download.set_fileobj(fobj)
else:
log.downloads.error("Unknown download target: {}".format(target))
def _open_download(self, download):
"""Open the given download but only if it was successful."""
if download.successful:
download.open_file()
else:
log.downloads.debug("{} finished but not successful, not opening!"
.format(download))
def raise_no_download(self, count):
"""Raise an exception that the download doesn't exist.
@@ -1316,6 +1331,11 @@ class TempDownloadManager(QObject):
A tempfile.NamedTemporaryFile that should be used to save the file.
"""
tmpdir = self._get_tmpdir()
encoding = sys.getfilesystemencoding()
suggested_name = utils.force_encoding(suggested_name, encoding)
# Make sure that the filename is not too long
if len(suggested_name) > 50:
suggested_name = suggested_name[:25] + '...' + suggested_name[-25:]
fobj = tempfile.NamedTemporaryFile(dir=tmpdir.name, delete=False,
suffix=suggested_name)
self.files.append(fobj)

View File

@@ -295,6 +295,10 @@ class WebHistory(QObject):
"""
if config.get('general', 'private-browsing'):
return
if not url.isValid():
log.misc.warning("Ignoring invalid URL being added to history")
return
if atime is None:
atime = time.time()
entry = Entry(atime, url, title, redirect=redirect)

View File

@@ -52,7 +52,8 @@ SELECTORS = {
Group.focus: '*:focus',
Group.inputs: ('input[type=text], input[type=email], input[type=url], '
'input[type=tel], input[type=number], '
'input[type=password], input[type=search], textarea'),
'input[type=password], input[type=search], '
'input:not([type]), textarea'),
}

View File

@@ -119,6 +119,9 @@ class CommandRunner(QObject):
Yields:
ParseResult tuples.
"""
if not text:
raise cmdexc.NoSuchCommandError("No command given")
if aliases:
text = self._get_alias(text, text)

View File

@@ -192,4 +192,4 @@ class UrlCompletionModel(base.BaseCompletionModel):
sibling = index.sibling(index.row(), self.TEXT_COLUMN)
qtutils.ensure_valid(sibling)
name = sibling.data()
quickmark_manager.quickmark_del(name)
quickmark_manager.delete(name)

View File

@@ -1458,8 +1458,8 @@ KEY_DATA = collections.OrderedDict([
('hint all hover', [';h']),
('hint images', [';i']),
('hint images tab', [';I']),
('hint links fill ":open {hint-url}"', [';o']),
('hint links fill ":open -t {hint-url}"', [';O']),
('hint links fill :open {hint-url}', [';o']),
('hint links fill :open -t {hint-url}', [';O']),
('hint links yank', [';y']),
('hint links yank-primary', [';Y']),
('hint --rapid links tab-bg', [';r']),
@@ -1649,4 +1649,6 @@ CHANGED_KEY_COMMANDS = [
(re.compile(r'^leave-mode$'), r'clear-keychain ;; leave-mode'),
(re.compile(r'^download-remove --all$'), r'download-clear'),
(re.compile(r'^hint links fill "([^"]*)"$'), r'hint links fill \1'),
]

View File

@@ -433,10 +433,10 @@ def update_settings(section, option):
QWebSettings.setIconDatabasePath('')
else:
QWebSettings.setIconDatabasePath(cache_path)
else:
try:
mapping = MAPPINGS[section][option]
except KeyError:
return
value = config.get(section, option)
mapping.set(value)
try:
mapping = MAPPINGS[section][option]
except KeyError:
return
value = config.get(section, option)
mapping.set(value)

View File

@@ -59,9 +59,13 @@ def _missing_str(name, *, windows=None, pip=None, webengine=False):
'distributions packages, or install it via pip.'.format(name)]
blocks.append('<br />'.join(lines))
if webengine:
lines = ['Note QtWebEngine is not available for some distributions '
'(like Debian/Ubuntu), so you need to start without '
'--backend webengine there.']
lines = [
'Note QtWebEngine is not available for some distributions '
'(like Debian/Ubuntu), so you need to start without '
'--backend webengine there.',
'QtWebEngine is currently unsupported with the OS X .app, see '
'https://github.com/The-Compiler/qutebrowser/issues/1692',
]
else:
lines = ['<b>If you installed a qutebrowser package for your '
'distribution, please report this as a bug.</b>']
@@ -166,8 +170,11 @@ def fix_harfbuzz(args):
from qutebrowser.utils import log
from PyQt5.QtCore import qVersion
if 'PyQt5.QtWidgets' in sys.modules:
log.init.warning("Harfbuzz fix attempted but QtWidgets is already "
"imported!")
msg = "Harfbuzz fix attempted but QtWidgets is already imported!"
if getattr(sys, 'frozen', False):
log.init.debug(msg)
else:
log.init.warning(msg)
if sys.platform.startswith('linux') and args.harfbuzz == 'auto':
if qVersion() == '5.3.0':
log.init.debug("Using new harfbuzz engine (auto)")

View File

@@ -168,7 +168,7 @@ def _from_args(typ, args):
suffix = basedir_suffix[typ]
except KeyError: # pragma: no cover
return (False, None)
return (True, os.path.join(basedir, suffix))
return (True, os.path.abspath(os.path.join(basedir, suffix)))
try:
argname = typ_to_argparse_arg[typ]

View File

@@ -24,7 +24,7 @@ SOURCE_DIR ?= .
SOURCE_FILES ?= dist/qutebrowser.app COPYING
TEMPLATE_DMG ?= template.dmg
TEMPLATE_SIZE ?= 120m
TEMPLATE_SIZE ?= 300m
################################################################################
# DMG building. No editing should be needed beyond this point.
@@ -37,17 +37,12 @@ WC_DIR=wc
.PHONY: all
all: $(MASTER_DMG)
$(TEMPLATE_DMG): $(TEMPLATE_DMG).bz2
bunzip2 -k $<
$(TEMPLATE_DMG).bz2:
$(TEMPLATE_DMG):
@echo
@echo --------------------- Generating empty template --------------------
mkdir template
hdiutil create -fs HFSX -layout SPUD -size $(TEMPLATE_SIZE) "$(TEMPLATE_DMG)" -srcfolder template -format UDRW -volname "$(NAME)" -quiet
rmdir template
bzip2 "$(TEMPLATE_DMG)"
@echo
$(WC_DMG): $(TEMPLATE_DMG)
cp $< $@

View File

@@ -28,6 +28,7 @@ import shutil
import subprocess
import argparse
import tarfile
import tempfile
import collections
sys.path.insert(0, os.path.join(os.path.dirname(__file__), os.pardir,
@@ -50,7 +51,7 @@ def call_script(name, *args, python=sys.executable):
subprocess.check_call([python, path] + list(args))
def call_tox(toxenv, *args, python=sys.executable):
def call_tox(toxenv, *args, python=os.path.dirname(sys.executable)):
"""Call tox.
Args:
@@ -94,7 +95,7 @@ def build_osx():
utils.print_title("Updating 3rdparty content")
update_3rdparty.update_pdfjs()
utils.print_title("Building .app via pyinstaller")
call_tox('pyinstaller')
call_tox('pyinstaller', '-r')
utils.print_title("Building .dmg")
subprocess.check_call(['make', '-f', 'scripts/dev/Makefile-dmg'])
utils.print_title("Cleaning up...")
@@ -103,6 +104,17 @@ def build_osx():
for d in ['dist', 'build']:
shutil.rmtree(d)
utils.print_title("Running smoke test")
with tempfile.TemporaryDirectory() as tmpdir:
subprocess.check_call(['hdiutil', 'attach', 'qutebrowser.dmg',
'-mountpoint', tmpdir])
try:
binary = os.path.join(tmpdir, 'qutebrowser.app', 'Contents',
'MacOS', 'qutebrowser')
smoke_test(binary)
finally:
subprocess.check_call(['hdiutil', 'detach', tmpdir])
def build_windows():
"""Build windows executables/setups."""
@@ -116,6 +128,8 @@ def build_windows():
python_x86 = r'C:\Python{}_x32'.format(ver)
python_x64 = r'C:\Python{}'.format(ver)
utils.print_title("Rebuilding tox environment")
call_tox('cxfreeze-windows', '-r', '--notest')
utils.print_title("Running 32bit freeze.py build_exe")
call_tox('cxfreeze-windows', 'build_exe', python=python_x86)
utils.print_title("Running 32bit freeze.py bdist_msi")

View File

@@ -49,6 +49,16 @@ def get_egl_path():
r'PyQt5\libEGL.dll')
def get_plugin_folders():
"""Get the plugin folders to copy to the output."""
if not sys.platform.startswith('win'):
return []
plugin_dir = os.path.join(distutils.sysconfig.get_python_lib(),
'PyQt5', 'plugins')
folders = ['audio', 'iconengines', 'mediaservice', 'printsupport']
return [os.path.join(plugin_dir, folder) for folder in folders]
def get_build_exe_options(skip_html=False):
"""Get the options passed as build_exe_options to cx_Freeze.
@@ -81,6 +91,8 @@ def get_build_exe_options(skip_html=False):
if egl_path is not None:
include_files.append((egl_path, 'libEGL.dll'))
include_files += get_plugin_folders()
return {
'include_files': include_files,
'include_msvcr': True,

View File

@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Simple input</title>
</head>
<body>
<form><input></input></form>
</body>
</html>

View File

@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
function check_storage() {
var elem = document.getElementById("status");
try {
localStorage.qute_test = "foo";
elem.innerHTML = "working";
} catch (e) {
elem.innerHTML = "not working";
}
}
</script>
</head>
<body onload="check_storage()">
<p>Local storage status: <span id="status">checking...</span></p>
</body>
</html>

View File

@@ -119,6 +119,15 @@ Feature: Using hints
And I run :follow-hint a
Then the error "Invalid link clicked - *" should be shown
Scenario: Hinting inputs without type
When I open data/hints/input.html
And I run :hint inputs
And I run :follow-hint a
And I wait for "Entering mode KeyMode.insert (reason: click)" in the log
And I run :leave-mode
# The actual check is already done above
Then no crash should happen
### iframes
Scenario: Using :follow-hint inside an iframe

View File

@@ -51,3 +51,12 @@ Feature: Page history
When I open data/title.html
And I run :history-clear
Then the history file should be empty
## Bugs
Scenario: Opening a valid URL which turns out invalid
When I set general -> auto-search to true
And I run :open http://foo%40bar@baz
Then "QFSFileEngine::open: No file name specified" should be logged
And "Error while loading : Host not found" should be logged
And "Ignoring invalid URL being added to history" should be logged

View File

@@ -471,6 +471,13 @@ Feature: Various utility commands.
And I open cookies in a new tab
Then the cookie qute-test should be set to 42
## https://github.com/The-Compiler/qutebrowser/issues/1742
Scenario: Private browsing is activated in QtWebKit without restart
When I set general -> private-browsing to true
And I open data/javascript/localstorage.html
Then the page should contain the plaintext "Local storage status: not working"
Scenario: :repeat-command
Given I open data/scroll.html
And I run :tab-only

View File

@@ -162,7 +162,7 @@ class SelectionAndFilterTests:
('<textarea />', [webelem.Group.all, webelem.Group.inputs]),
('<select />', [webelem.Group.all]),
('<input />', [webelem.Group.all]),
('<input />', [webelem.Group.all, webelem.Group.inputs]),
('<input type="hidden" />', []),
('<input type="text" />', [webelem.Group.inputs, webelem.Group.all]),
('<input type="email" />', [webelem.Group.inputs, webelem.Group.all]),

View File

@@ -53,6 +53,15 @@ class TestCommandRunner:
with pytest.raises(cmdexc.NoSuchCommandError):
list(cr.parse_all("alias_name"))
def test_parse_empty_with_alias(self):
"""An empty command should not crash.
See https://github.com/The-Compiler/qutebrowser/issues/1690
"""
cr = runners.CommandRunner(0)
with pytest.raises(cmdexc.NoSuchCommandError):
list(cr.parse_all(''))
def test_parse_with_count(self):
"""Test parsing of commands with a count."""
cr = runners.CommandRunner(0)

View File

@@ -281,6 +281,11 @@ class TestKeyConfigParser:
('leave-mode ;; foo', None),
('download-remove --all', 'download-clear'),
('hint links fill ":open {hint-url}"',
'hint links fill :open {hint-url}'),
('hint links fill ":open -t {hint-url}"',
'hint links fill :open -t {hint-url}'),
]
)
def test_migrations(self, old, new_expected):
@@ -329,7 +334,7 @@ class TestDefaultConfig:
If it did change, place a new qutebrowser-vx.y.z.conf in old_configs
and then increment the version.
"""
assert qutebrowser.__version__ == '0.8.0'
assert qutebrowser.__version__ == '0.8.2'
@pytest.mark.parametrize('filename',
os.listdir(os.path.join(os.path.dirname(__file__), 'old_configs')),

View File

@@ -532,32 +532,33 @@ class TestSendToRunningInstance:
@pytest.mark.linux(reason="Causes random trouble on Windows and OS X")
def test_normal(self, qtbot, tmpdir, ipc_server, mocker, has_cwd):
ipc_server.listen()
raw_spy = QSignalSpy(ipc_server.got_raw)
with qtbot.assertNotEmitted(ipc_server.got_invalid_data):
with qtbot.waitSignal(ipc_server.got_args,
timeout=5000) as blocker:
with tmpdir.as_cwd():
if not has_cwd:
m = mocker.patch('qutebrowser.misc.ipc.os')
m.getcwd.side_effect = OSError
sent = ipc.send_to_running_instance('qute-test', ['foo'],
None)
with qtbot.waitSignal(ipc_server.got_raw,
timeout=5000) as raw_blocker:
with tmpdir.as_cwd():
if not has_cwd:
m = mocker.patch('qutebrowser.misc.ipc.os')
m.getcwd.side_effect = OSError
sent = ipc.send_to_running_instance(
'qute-test', ['foo'], None)
assert sent
assert sent
expected_cwd = str(tmpdir) if has_cwd else ''
assert blocker.args == [['foo'], '', expected_cwd]
assert len(raw_spy) == 1
assert len(raw_spy[0]) == 1
raw_expected = {'args': ['foo'], 'target_arg': None,
'version': qutebrowser.__version__,
'protocol_version': ipc.PROTOCOL_VERSION}
if has_cwd:
raw_expected['cwd'] = str(tmpdir)
parsed = json.loads(raw_spy[0][0].decode('utf-8'))
assert len(raw_blocker.args) == 1
parsed = json.loads(raw_blocker.args[0].decode('utf-8'))
assert parsed == raw_expected
def test_socket_error(self):

View File

@@ -225,6 +225,15 @@ class TestArguments:
func = getattr(standarddir, typ)
assert func() == expected
def test_basedir_relative(self, tmpdir):
"""Test --basedir with a relative path."""
basedir = (tmpdir / 'basedir')
basedir.ensure(dir=True)
with tmpdir.as_cwd():
args = types.SimpleNamespace(basedir='basedir')
standarddir.init(args)
assert standarddir.config() == str(basedir / 'config')
class TestInitCacheDirTag:
@@ -311,6 +320,7 @@ class TestCreatingDir:
m.sep = os.sep
m.path.join = os.path.join
m.path.exists.return_value = False
m.path.abspath = lambda x: x
args = types.SimpleNamespace(basedir=str(tmpdir))
standarddir.init(args)