summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortoofar <toofar@spalge.com>2023-08-14 15:42:38 +1200
committerGitHub <noreply@github.com>2023-08-14 15:42:38 +1200
commit65750e4b5459a933d3013bbb7e19cbeb292ff200 (patch)
tree7ed2b659ef09fc65084f4eee6dab26814be76a09
parent1dba77ddb31fc0b861cffacc64beb04666e273ac (diff)
parent7599dbc2090466ecac8c75ac5c36ec9ffbd882b2 (diff)
downloadqutebrowser-65750e4b5459a933d3013bbb7e19cbeb292ff200.tar.gz
qutebrowser-65750e4b5459a933d3013bbb7e19cbeb292ff200.zip
Merge pull request #7803 from qutebrowser/feat/mac_sandbox_pre_release_pyinstaller
Feat/mac sandbox pre release pyinstaller
-rw-r--r--doc/changelog.asciidoc2
-rwxr-xr-xmisc/nsis/install.nsh33
-rwxr-xr-xmisc/nsis/qutebrowser.nsi7
-rw-r--r--misc/qutebrowser.spec19
-rw-r--r--misc/requirements/requirements-pyinstaller.txt2
-rw-r--r--misc/requirements/requirements-pyinstaller.txt-raw2
-rw-r--r--qutebrowser/app.py9
-rw-r--r--qutebrowser/browser/qutescheme.py3
-rw-r--r--qutebrowser/extensions/loader.py28
-rw-r--r--qutebrowser/html/warning-sandboxing.html16
-rw-r--r--qutebrowser/utils/resources.py5
-rwxr-xr-xscripts/dev/build_release.py67
-rw-r--r--tests/unit/extensions/test_loader.py8
-rw-r--r--tox.ini2
14 files changed, 88 insertions, 115 deletions
diff --git a/doc/changelog.asciidoc b/doc/changelog.asciidoc
index 5deb381f7..96a4b42e7 100644
--- a/doc/changelog.asciidoc
+++ b/doc/changelog.asciidoc
@@ -88,7 +88,7 @@ Removed
* Qt 6.4 was the latest version to support macOS 10.14 and 10.15.
* It should be possible to build a custom .dmg with Qt 6.4, but this is
unsupported and not recommended.
-- Support for Windows 8 and for Windows 10 before 1809 is now dropped.
+- Support for Windows 8 and for Windows 10 before 1607 is now dropped.
* Support for older Windows 10 versions might still be present in Qt 6.0/6.1/6.2
* Support for Windows 8.1 is still present in Qt 5.15
* It should be possible to build a custom .exe with those versions, but this
diff --git a/misc/nsis/install.nsh b/misc/nsis/install.nsh
index e7d8b4956..282a254eb 100755
--- a/misc/nsis/install.nsh
+++ b/misc/nsis/install.nsh
@@ -430,8 +430,37 @@ SectionEnd
; Callbacks
Function .onInit
StrCpy $KeepReg 1
- !insertmacro CheckPlatform ${PLATFORM}
- !insertmacro CheckMinWinVer ${MIN_WIN_VER}
+
+; OS version check
+ ${If} ${RunningX64}
+ ; https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-osversioninfoa#remarks
+ GetWinVer $R0 Major
+ !if "${QT5}" == "True"
+ IntCmpU $R0 6 0 _os_check_fail _os_check_pass
+ GetWinVer $R1 Minor
+ IntCmpU $R1 2 _os_check_pass _os_check_fail _os_check_pass
+ !else
+ IntCmpU $R0 10 0 _os_check_fail _os_check_pass
+ GetWinVer $R1 Build
+ ${If} $R1 >= 22000 ; Windows 11 21H2
+ Goto _os_check_pass
+ ${ElseIf} $R1 >= 14393 ; Windows 10 1607
+ ${AndIf} ${IsNativeAMD64} ; Windows 10 has no x86_64 emulation on arm64
+ Goto _os_check_pass
+ ${EndIf}
+ !endif
+ ${EndIf}
+ _os_check_fail:
+ !if "${QT5}" == "True"
+ MessageBox MB_OK|MB_ICONSTOP "This version of ${PRODUCT_NAME} requires a 64-bit$\r$\n\
+ version of Windows 8 or later."
+ !else
+ MessageBox MB_OK|MB_ICONSTOP "This version of ${PRODUCT_NAME} requires a 64-bit$\r$\n\
+ version of Windows 10 1607 or later."
+ !endif
+ Abort
+ _os_check_pass:
+
${ifnot} ${UAC_IsInnerInstance}
!insertmacro CheckSingleInstance "Setup" "Global" "${SETUP_MUTEX}"
!insertmacro CheckSingleInstance "Application" "Local" "${APP_MUTEX}"
diff --git a/misc/nsis/qutebrowser.nsi b/misc/nsis/qutebrowser.nsi
index 60b174bdd..bd5156e83 100755
--- a/misc/nsis/qutebrowser.nsi
+++ b/misc/nsis/qutebrowser.nsi
@@ -124,13 +124,16 @@ ShowUninstDetails hide
; If not defined, get VERSION from PROGEXE. Set DIST_DIR accordingly.
!ifndef VERSION
- !define /ifndef DIST_DIR ".\..\..\dist\${PRODUCT_NAME}-${ARCH}"
+ !define /ifndef DIST_DIR ".\..\..\dist\${PRODUCT_NAME}"
!getdllversion "${DIST_DIR}\${PROGEXE}" expv_
!define VERSION "${expv_1}.${expv_2}.${expv_3}"
!else
- !define /ifndef DIST_DIR ".\..\..\dist\${PRODUCT_NAME}-${VERSION}-${ARCH}"
+ !define /ifndef DIST_DIR ".\..\..\dist\${PRODUCT_NAME}-${VERSION}"
!endif
+; If not defined, assume Qt6 (requires a more recent windows version)
+!define /ifndef QT5 "False"
+
; Pack the exe header with upx if UPX is defined.
!ifdef UPX
!packhdr "$%TEMP%\exehead.tmp" '"upx" "--ultra-brute" "$%TEMP%\exehead.tmp"'
diff --git a/misc/qutebrowser.spec b/misc/qutebrowser.spec
index 1eee9161d..ecb9da68e 100644
--- a/misc/qutebrowser.spec
+++ b/misc/qutebrowser.spec
@@ -64,17 +64,17 @@ INFO_PLIST_UPDATES = {
def get_data_files():
data_files = [
- ('../qutebrowser/html', 'html'),
- ('../qutebrowser/img', 'img'),
- ('../qutebrowser/icons', 'icons'),
- ('../qutebrowser/javascript', 'javascript'),
- ('../qutebrowser/html/doc', 'html/doc'),
- ('../qutebrowser/git-commit-id', '.'),
- ('../qutebrowser/config/configdata.yml', 'config'),
+ ('../qutebrowser/html', 'qutebrowser/html'),
+ ('../qutebrowser/img', 'qutebrowser/img'),
+ ('../qutebrowser/icons', 'qutebrowser/icons'),
+ ('../qutebrowser/javascript', 'qutebrowser/javascript'),
+ ('../qutebrowser/html/doc', 'qutebrowser/html/doc'),
+ ('../qutebrowser/git-commit-id', 'qutebrowser/git-commit-id'),
+ ('../qutebrowser/config/configdata.yml', 'qutebrowser/config'),
]
if os.path.exists(os.path.join('qutebrowser', '3rdparty', 'pdfjs')):
- data_files.append(('../qutebrowser/3rdparty/pdfjs', '3rdparty/pdfjs'))
+ data_files.append(('../qutebrowser/3rdparty/pdfjs', 'qutebrowser/3rdparty/pdfjs'))
else:
print("Warning: excluding pdfjs as it's not present!")
@@ -137,5 +137,4 @@ app = BUNDLE(coll,
name='qutebrowser.app',
icon=icon,
info_plist=INFO_PLIST_UPDATES,
- # https://github.com/pyinstaller/pyinstaller/blob/b78bfe530cdc2904f65ce098bdf2de08c9037abb/PyInstaller/hooks/hook-PyQt5.QtWebEngineWidgets.py#L24
- bundle_identifier='org.qt-project.Qt.QtWebEngineCore')
+ bundle_identifier='org.qutebrowser.qutebrowser')
diff --git a/misc/requirements/requirements-pyinstaller.txt b/misc/requirements/requirements-pyinstaller.txt
index 912b38cd3..b112963b0 100644
--- a/misc/requirements/requirements-pyinstaller.txt
+++ b/misc/requirements/requirements-pyinstaller.txt
@@ -1,5 +1,5 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
altgraph==0.17.3
-pyinstaller==5.13.0
+pyinstaller @ git+https://github.com/pyinstaller/pyinstaller.git@79f62ef29822169ae00cd4271390d0e3175476ad
pyinstaller-hooks-contrib==2023.6
diff --git a/misc/requirements/requirements-pyinstaller.txt-raw b/misc/requirements/requirements-pyinstaller.txt-raw
index c313980b0..7b4c8c84c 100644
--- a/misc/requirements/requirements-pyinstaller.txt-raw
+++ b/misc/requirements/requirements-pyinstaller.txt-raw
@@ -1 +1 @@
-PyInstaller
+pyinstaller @ git+https://github.com/pyinstaller/pyinstaller.git@79f62ef29822169ae00cd4271390d0e3175476ad
diff --git a/qutebrowser/app.py b/qutebrowser/app.py
index 94cc53c72..60eedeb1b 100644
--- a/qutebrowser/app.py
+++ b/qutebrowser/app.py
@@ -346,15 +346,6 @@ def _open_special_pages(args):
True,
'qute://warning/sessions'),
- ('sandboxing-warning-shown',
- (
- hasattr(sys, "frozen") and
- utils.is_mac and
- machinery.IS_QT6 and
- os.environ.get("QTWEBENGINE_DISABLE_SANDBOX") == "1"
- ),
- 'qute://warning/sandboxing'),
-
('qt5-warning-shown',
(
machinery.IS_QT5 and
diff --git a/qutebrowser/browser/qutescheme.py b/qutebrowser/browser/qutescheme.py
index dae862b8b..f325ff9e3 100644
--- a/qutebrowser/browser/qutescheme.py
+++ b/qutebrowser/browser/qutescheme.py
@@ -568,9 +568,6 @@ def qute_warning(url: QUrl) -> _HandlerRet:
title='Qt 5.15 sessions warning',
datadir=standarddir.data(),
sep=os.sep)
- elif path == '/sandboxing':
- src = jinja.render('warning-sandboxing.html',
- title='Qt 6 macOS sandboxing warning')
elif path == '/qt5':
is_venv = hasattr(sys, 'real_prefix') or sys.base_prefix != sys.prefix
src = jinja.render('warning-qt5.html',
diff --git a/qutebrowser/extensions/loader.py b/qutebrowser/extensions/loader.py
index b5b232c5a..7ccdabc88 100644
--- a/qutebrowser/extensions/loader.py
+++ b/qutebrowser/extensions/loader.py
@@ -6,11 +6,12 @@
import pkgutil
import types
+import sys
import pathlib
import importlib
import argparse
import dataclasses
-from typing import Callable, Iterator, List, Optional, Tuple
+from typing import Callable, Iterator, List, Optional, Set, Tuple
from qutebrowser.qt.core import pyqtSlot
@@ -79,6 +80,14 @@ def load_components(*, skip_hooks: bool = False) -> None:
def walk_components() -> Iterator[ExtensionInfo]:
"""Yield ExtensionInfo objects for all modules."""
+ if hasattr(sys, 'frozen'):
+ yield from _walk_pyinstaller()
+ else:
+ yield from _walk_normal()
+
+
+def _walk_normal() -> Iterator[ExtensionInfo]:
+ """Walk extensions when not using PyInstaller."""
for _finder, name, ispkg in pkgutil.walk_packages(
path=components.__path__,
prefix=components.__name__ + '.',
@@ -93,6 +102,23 @@ def walk_components() -> Iterator[ExtensionInfo]:
yield ExtensionInfo(name=name)
+def _walk_pyinstaller() -> Iterator[ExtensionInfo]:
+ """Walk extensions when using PyInstaller.
+
+ See https://github.com/pyinstaller/pyinstaller/issues/1905
+
+ Inspired by:
+ https://github.com/webcomics/dosage/blob/master/dosagelib/loader.py
+ """
+ toc: Set[str] = set()
+ for importer in pkgutil.iter_importers('qutebrowser'):
+ if hasattr(importer, 'toc'):
+ toc |= importer.toc
+ for name in toc:
+ if name.startswith(components.__name__ + '.'):
+ yield ExtensionInfo(name=name)
+
+
def _get_init_context() -> InitContext:
"""Get an InitContext object."""
return InitContext(data_dir=pathlib.Path(standarddir.data()),
diff --git a/qutebrowser/html/warning-sandboxing.html b/qutebrowser/html/warning-sandboxing.html
deleted file mode 100644
index 186d938e7..000000000
--- a/qutebrowser/html/warning-sandboxing.html
+++ /dev/null
@@ -1,16 +0,0 @@
-{% extends "styled.html" %}
-
-{% block content %}
-<h1>{{ title }}</h1>
-<span class="note">Note this warning will only appear once. Use <span class="mono">:open
-qute://warning/sandboxing</span> to show it again at a later time.</span>
-
-<p>
- Due to a <a href="https://github.com/pyinstaller/pyinstaller/pull/6903">PyInstaller issue</a>,
- Chromium's <a href="https://chromium.googlesource.com/chromium/src/+/HEAD/docs/design/sandbox_faq.md">sandboxing</a>
- is currently disabled for macOS builds with Qt 6. This means that there will be no additional layer of protection
- in case of Chromium security bugs. Thus, it's advised to
- <b>not use this build in production</b>. Hopefully, this situation will be
- resolved before the final 3.0.0 release.
-</p>
-{% endblock %}
diff --git a/qutebrowser/utils/resources.py b/qutebrowser/utils/resources.py
index 494f01bff..60d90fd31 100644
--- a/qutebrowser/utils/resources.py
+++ b/qutebrowser/utils/resources.py
@@ -36,11 +36,6 @@ def _path(filename: str) -> _ResourceType:
assert not posixpath.isabs(filename), filename
assert os.path.pardir not in filename.split(posixpath.sep), filename
- if hasattr(sys, 'frozen'):
- # For PyInstaller, where we can't store resource files in a qutebrowser/ folder
- # because the executable is already named "qutebrowser" (at least on macOS).
- return pathlib.Path(sys.executable).parent / filename
-
return importlib_resources.files(qutebrowser) / filename
@contextlib.contextmanager
diff --git a/scripts/dev/build_release.py b/scripts/dev/build_release.py
index 73689ea88..a638508de 100755
--- a/scripts/dev/build_release.py
+++ b/scripts/dev/build_release.py
@@ -171,9 +171,6 @@ def smoke_test(executable: pathlib.Path, debug: bool, qt5: bool) -> None:
r'[0-9:]* WARNING: Qt WebEngine resources not found at .*',
(r'[0-9:]* WARNING: Installed Qt WebEngine locales directory not found at '
r'location /qtwebengine_locales\. Trying application directory\.\.\.'),
-
- # https://github.com/pyinstaller/pyinstaller/pull/6903
- r"[0-9:]* INFO: Sandboxing disabled by user\.",
])
elif IS_WINDOWS:
stderr_whitelist.extend([
@@ -245,66 +242,11 @@ def verify_windows_exe(exe_path: pathlib.Path) -> None:
assert pe.verify_checksum()
-def patch_mac_app(qt5: bool) -> None:
- """Patch .app to save some space and make it signable."""
- dist_path = pathlib.Path('dist')
- ver = '5' if qt5 else '6'
- app_path = dist_path / 'qutebrowser.app'
-
- contents_path = app_path / 'Contents'
- macos_path = contents_path / 'MacOS'
- resources_path = contents_path / 'Resources'
- pyqt_path = macos_path / f'PyQt{ver}'
-
- # Replace some duplicate files by symlinks
- framework_path = pyqt_path / f'Qt{ver}' / 'lib' / 'QtWebEngineCore.framework'
-
- framework_resource_path = framework_path / 'Resources'
- for file_path in framework_resource_path.iterdir():
- target = pathlib.Path(*[os.pardir] * 5, file_path.name)
- if file_path.is_dir():
- shutil.rmtree(file_path)
- else:
- file_path.unlink()
- file_path.symlink_to(target)
-
- if not qt5:
- # Symlinking QtWebEngineCore.framework does not seem to work with Qt 6.
- # Also, the symlinking/moving before signing doesn't seem to be required.
- return
-
- core_lib = framework_path / 'Versions' / '5' / 'QtWebEngineCore'
- core_lib.unlink()
- core_target = pathlib.Path(*[os.pardir] * 7, 'MacOS', 'QtWebEngineCore')
- core_lib.symlink_to(core_target)
-
- # Move stuff around to make things signable on macOS
- # See https://github.com/pyinstaller/pyinstaller/issues/6612
- pyqt_path_dest = resources_path / pyqt_path.name
- shutil.move(pyqt_path, pyqt_path_dest)
- pyqt_path_target = pathlib.Path("..") / pyqt_path_dest.relative_to(contents_path)
- pyqt_path.symlink_to(pyqt_path_target)
-
- for path in macos_path.glob("Qt*"):
- link_path = resources_path / path.name
- target_path = pathlib.Path("..") / path.relative_to(contents_path)
- link_path.symlink_to(target_path)
-
-
-def sign_mac_app() -> None:
+def verify_mac_app() -> None:
"""Re-sign and verify the Mac .app."""
app_path = pathlib.Path('dist') / 'qutebrowser.app'
subprocess.run([
'codesign',
- '-s', '-',
- '--force',
- '--timestamp',
- '--deep',
- '--verbose',
- app_path,
- ], check=True)
- subprocess.run([
- 'codesign',
'--verify',
'--strict',
'--deep',
@@ -341,10 +283,8 @@ def build_mac(
utils.print_title("Building .app via pyinstaller")
call_tox(f'pyinstaller{"-qt5" if qt5 else ""}', '-r', debug=debug)
- utils.print_title("Patching .app")
- patch_mac_app(qt5=qt5)
- utils.print_title("Re-signing .app")
- sign_mac_app()
+ utils.print_title("Verifying .app")
+ verify_mac_app()
dist_path = pathlib.Path("dist")
@@ -483,6 +423,7 @@ def _package_windows_single(
utils.print_subtitle("Building installer...")
subprocess.run(['makensis.exe',
f'/DVERSION={qutebrowser.__version__}',
+ f'/DQT5={qt5}',
'misc/nsis/qutebrowser.nsi'], check=True)
name_parts = [
diff --git a/tests/unit/extensions/test_loader.py b/tests/unit/extensions/test_loader.py
index a2a99f305..fd15130ba 100644
--- a/tests/unit/extensions/test_loader.py
+++ b/tests/unit/extensions/test_loader.py
@@ -20,10 +20,16 @@ def test_on_walk_error():
def test_walk_normal():
- names = [info.name for info in loader.walk_components()]
+ names = [info.name for info in loader._walk_normal()]
assert 'qutebrowser.components.scrollcommands' in names
+def test_walk_pyinstaller():
+ # We can't test whether we get something back without being frozen by
+ # PyInstaller, but at least we can test that we don't crash.
+ list(loader._walk_pyinstaller())
+
+
def test_load_component(monkeypatch):
monkeypatch.setattr(objects, 'commands', {})
diff --git a/tox.ini b/tox.ini
index 541effc2c..0014f261c 100644
--- a/tox.ini
+++ b/tox.ini
@@ -187,6 +187,7 @@ passenv =
APPDATA
HOME
PYINSTALLER_DEBUG
+ PYINSTALLER_COMPILE_BOOTLOADER
setenv =
qt5: PYINSTALLER_QT5=true
deps =
@@ -268,6 +269,7 @@ passenv = *
# Override default PyQt6 from [testenv]
setenv =
qt5: QUTE_QT_WRAPPER=PyQt5
+ PYINSTALLER_COMPILE_BOOTLOADER=true
usedevelop = true
deps =
-r{toxinidir}/requirements.txt