From 31b63e547156870a969a5744e297b0460bb6e009 Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Mon, 26 Oct 2020 14:52:45 -0700 Subject: [PATCH 1/9] Start switching from PyQt5 to PySide2 --- BUILD.md | 4 ++-- dangerzone/doc_selection_widget.py | 4 ++-- dangerzone/docker_installer.py | 8 ++++---- dangerzone/global_common.py | 2 +- dangerzone/gui.py | 6 +++--- dangerzone/main_window.py | 4 ++-- dangerzone/settings_widget.py | 6 +++--- dangerzone/tasks.py | 10 +++++----- dangerzone/tasks_widget.py | 4 ++-- 9 files changed, 24 insertions(+), 24 deletions(-) diff --git a/BUILD.md b/BUILD.md index bf8971d..87c9c7b 100644 --- a/BUILD.md +++ b/BUILD.md @@ -5,10 +5,10 @@ Install dependencies: ```sh -sudo apt install -y python-all dh-python python3-stdeb python3 python3-pyqt5 python3-appdirs python3-click python3-xdg python3-requests python3-termcolor +sudo apt install -y python3 python3-stdeb python3-pyside2.qtcore python3-pyside2.qtgui python3-pyside2.qtwidgets python3-appdirs python3-click python3-xdg python3-requests python3-termcolor ``` -You also need docker, either by installing the `docker.io` package, or by installing `docker-ce` by following [these instructions for Ubuntu](https://docs.docker.com/install/linux/docker-ce/ubuntu/) or [for Debian](https://docs.docker.com/install/linux/docker-ce/debian/). +You also need docker, either by installing the `docker.io` package, or by installing `docker-ce` by following [these instructions for Ubuntu](https://docs.docker.com/install/linux/docker-ce/ubuntu/) or [for Debian](https://docs.docker.com/install/linux/docker-ce/debian/), or installing the [Docker snap package](https://snapcraft.io/docker). Run from source tree: diff --git a/dangerzone/doc_selection_widget.py b/dangerzone/doc_selection_widget.py index 5609135..c7d8506 100644 --- a/dangerzone/doc_selection_widget.py +++ b/dangerzone/doc_selection_widget.py @@ -1,8 +1,8 @@ -from PyQt5 import QtCore, QtGui, QtWidgets +from PySide2 import QtCore, QtGui, QtWidgets class DocSelectionWidget(QtWidgets.QWidget): - document_selected = QtCore.pyqtSignal() + document_selected = QtCore.Signal() def __init__(self, common): super(DocSelectionWidget, self).__init__() diff --git a/dangerzone/docker_installer.py b/dangerzone/docker_installer.py index 6a7596d..6398631 100644 --- a/dangerzone/docker_installer.py +++ b/dangerzone/docker_installer.py @@ -6,7 +6,7 @@ import subprocess import shutil import time import platform -from PyQt5 import QtCore, QtGui, QtWidgets +from PySide2 import QtCore, QtGui, QtWidgets from .container import container_runtime @@ -194,9 +194,9 @@ class DockerInstaller(QtWidgets.QDialog): class Downloader(QtCore.QThread): - download_finished = QtCore.pyqtSignal() - download_failed = QtCore.pyqtSignal(int) - update_progress = QtCore.pyqtSignal(int, int) + download_finished = QtCore.Signal() + download_failed = QtCore.Signal(int) + update_progress = QtCore.Signal(int, int) def __init__(self, installer_filename): super(Downloader, self).__init__() diff --git a/dangerzone/global_common.py b/dangerzone/global_common.py index ab88d14..0e4aa54 100644 --- a/dangerzone/global_common.py +++ b/dangerzone/global_common.py @@ -7,7 +7,7 @@ import platform import subprocess import shlex import pipes -from PyQt5 import QtCore, QtGui, QtWidgets +from PySide2 import QtCore, QtGui, QtWidgets if platform.system() == "Darwin": import CoreServices diff --git a/dangerzone/gui.py b/dangerzone/gui.py index ec83a1e..60602b7 100644 --- a/dangerzone/gui.py +++ b/dangerzone/gui.py @@ -1,4 +1,3 @@ -from PyQt5 import QtCore, QtWidgets import os import sys import signal @@ -7,6 +6,7 @@ import click import time import uuid import subprocess +from PySide2 import QtCore, QtWidgets from .global_common import GlobalCommon from .main_window import MainWindow @@ -21,8 +21,8 @@ from .container import container_runtime class Application(QtWidgets.QApplication): - document_selected = QtCore.pyqtSignal(str) - application_activated = QtCore.pyqtSignal() + document_selected = QtCore.Signal(str) + application_activated = QtCore.Signal() def __init__(self): QtWidgets.QApplication.__init__(self, sys.argv) diff --git a/dangerzone/main_window.py b/dangerzone/main_window.py index 38789d9..209af08 100644 --- a/dangerzone/main_window.py +++ b/dangerzone/main_window.py @@ -1,7 +1,7 @@ import shutil import os import platform -from PyQt5 import QtCore, QtGui, QtWidgets +from PySide2 import QtCore, QtGui, QtWidgets from .doc_selection_widget import DocSelectionWidget from .settings_widget import SettingsWidget @@ -10,7 +10,7 @@ from .common import Common class MainWindow(QtWidgets.QMainWindow): - delete_window = QtCore.pyqtSignal(str) + delete_window = QtCore.Signal(str) def __init__(self, global_common, window_id): super(MainWindow, self).__init__() diff --git a/dangerzone/settings_widget.py b/dangerzone/settings_widget.py index c3cbfc3..22a15e0 100644 --- a/dangerzone/settings_widget.py +++ b/dangerzone/settings_widget.py @@ -1,12 +1,12 @@ import os import subprocess import platform -from PyQt5 import QtCore, QtGui, QtWidgets +from PySide2 import QtCore, QtGui, QtWidgets class SettingsWidget(QtWidgets.QWidget): - start_clicked = QtCore.pyqtSignal() - close_window = QtCore.pyqtSignal() + start_clicked = QtCore.Signal() + close_window = QtCore.Signal() def __init__(self, global_common, common): super(SettingsWidget, self).__init__() diff --git a/dangerzone/tasks.py b/dangerzone/tasks.py index e19f459..bf950a3 100644 --- a/dangerzone/tasks.py +++ b/dangerzone/tasks.py @@ -3,15 +3,15 @@ import time import os import pipes import platform -from PyQt5 import QtCore, QtWidgets, QtGui +from PySide2 import QtCore, QtWidgets, QtGui from termcolor import cprint class TaskBase(QtCore.QThread): - task_finished = QtCore.pyqtSignal() - task_failed = QtCore.pyqtSignal(str) - update_label = QtCore.pyqtSignal(str) - update_details = QtCore.pyqtSignal(str) + task_finished = QtCore.Signal() + task_failed = QtCore.Signal(str) + update_label = QtCore.Signal(str) + update_details = QtCore.Signal(str) def __init__(self): super(TaskBase, self).__init__() diff --git a/dangerzone/tasks_widget.py b/dangerzone/tasks_widget.py index a8436ac..4688d36 100644 --- a/dangerzone/tasks_widget.py +++ b/dangerzone/tasks_widget.py @@ -3,13 +3,13 @@ import tempfile import os import platform import subprocess -from PyQt5 import QtCore, QtGui, QtWidgets +from PySide2 import QtCore, QtGui, QtWidgets from .tasks import PullImageTask, ConvertToPixels, ConvertToPDF class TasksWidget(QtWidgets.QWidget): - close_window = QtCore.pyqtSignal() + close_window = QtCore.Signal() def __init__(self, global_common, common): super(TasksWidget, self).__init__() From 92b19fe1b390b82915fe299712674d465f1da867 Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Mon, 26 Oct 2020 15:11:41 -0700 Subject: [PATCH 2/9] Allow docker installed from snap package --- dangerzone/common.py | 18 +++++++++++++++--- dangerzone/container.py | 3 ++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/dangerzone/common.py b/dangerzone/common.py index 9b479c7..637b26b 100644 --- a/dangerzone/common.py +++ b/dangerzone/common.py @@ -1,3 +1,4 @@ +import os import platform import tempfile @@ -8,16 +9,27 @@ class Common(object): """ def __init__(self): - # Temporary directory to store pixel data - # Note in macOS, temp dirs must be in /tmp (or a few other paths) for Docker to mount them + # Temporary directory to store pixel data and safe PDFs if platform.system() == "Windows": self.pixel_dir = tempfile.TemporaryDirectory(prefix="dangerzone-pixel-") self.safe_dir = tempfile.TemporaryDirectory(prefix="dangerzone-safe-") - else: + elif platform.system() == "Darwin": + # In macOS, temp dirs must be in /tmp (or a few other paths) for Docker to mount them self.pixel_dir = tempfile.TemporaryDirectory( prefix="/tmp/dangerzone-pixel-" ) self.safe_dir = tempfile.TemporaryDirectory(prefix="/tmp/dangerzone-safe-") + else: + # In Linux, temp dirs must be in the homedir for the snap package version of Docker to mount them + cache_dir = os.path.expanduser("~/.cache/dangerzone") + os.makedirs(cache_dir, exist_ok=True) + self.pixel_dir = tempfile.TemporaryDirectory( + prefix=os.path.join(cache_dir, "pixel-") + ) + self.safe_dir = tempfile.TemporaryDirectory( + prefix=os.path.join(cache_dir, "safe-") + ) + print( f"Temporary directories created, dangerous={self.pixel_dir.name}, safe={self.safe_dir.name}" ) diff --git a/dangerzone/container.py b/dangerzone/container.py index ab1bd98..a47f5b6 100644 --- a/dangerzone/container.py +++ b/dangerzone/container.py @@ -4,6 +4,7 @@ import subprocess import sys import pipes import getpass +import shutil # What is the container runtime for this platform? if platform.system() == "Darwin": @@ -11,7 +12,7 @@ if platform.system() == "Darwin": elif platform.system() == "Windows": container_runtime = "C:\\Program Files\\Docker\\Docker\\resources\\bin\\docker.exe" else: - container_runtime = "/usr/bin/docker" + container_runtime = shutil.which("docker") # Define startupinfo for subprocesses if platform.system() == "Windows": From 50044a05fa7a132e05cadb718c5dcd2af0e83d2a Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Mon, 26 Oct 2020 15:12:17 -0700 Subject: [PATCH 3/9] Remove QVariant, to finish porting from PyQt5 to PySide2 --- dangerzone/settings_widget.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/dangerzone/settings_widget.py b/dangerzone/settings_widget.py index 22a15e0..4150653 100644 --- a/dangerzone/settings_widget.py +++ b/dangerzone/settings_widget.py @@ -50,9 +50,7 @@ class SettingsWidget(QtWidgets.QWidget): self.open_checkbox.clicked.connect(self.update_ui) self.open_combobox = QtWidgets.QComboBox() for k in self.global_common.pdf_viewers: - self.open_combobox.addItem( - k, QtCore.QVariant(self.global_common.pdf_viewers[k]) - ) + self.open_combobox.addItem(k, self.global_common.pdf_viewers[k]) open_layout = QtWidgets.QHBoxLayout() open_layout.addWidget(self.open_checkbox) open_layout.addWidget(self.open_combobox) @@ -62,9 +60,7 @@ class SettingsWidget(QtWidgets.QWidget): self.ocr_checkbox = QtWidgets.QCheckBox("OCR document, language") self.ocr_combobox = QtWidgets.QComboBox() for k in self.global_common.ocr_languages: - self.ocr_combobox.addItem( - k, QtCore.QVariant(self.global_common.ocr_languages[k]) - ) + self.ocr_combobox.addItem(k, self.global_common.ocr_languages[k]) ocr_layout = QtWidgets.QHBoxLayout() ocr_layout.addWidget(self.ocr_checkbox) ocr_layout.addWidget(self.ocr_combobox) @@ -143,7 +139,10 @@ class SettingsWidget(QtWidgets.QWidget): self.update_checkbox.hide() else: with self.global_common.exec_dangerzone_container( - ["ls", self.global_common.get_container_name(),] + [ + "ls", + self.global_common.get_container_name(), + ] ) as p: stdout_data, stderror_data = p.communicate() From ab261e8270abee3228df05252353e29af896b75a Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Mon, 26 Oct 2020 16:30:33 -0700 Subject: [PATCH 4/9] Update linux build instructions --- BUILD.md | 4 ++-- stdeb.cfg | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/BUILD.md b/BUILD.md index 87c9c7b..9d60a67 100644 --- a/BUILD.md +++ b/BUILD.md @@ -5,10 +5,10 @@ Install dependencies: ```sh -sudo apt install -y python3 python3-stdeb python3-pyside2.qtcore python3-pyside2.qtgui python3-pyside2.qtwidgets python3-appdirs python3-click python3-xdg python3-requests python3-termcolor +sudo apt install -y dh-python python3 python3-stdeb python3-pyside2.qtcore python3-pyside2.qtgui python3-pyside2.qtwidgets python3-appdirs python3-click python3-xdg python3-requests python3-termcolor ``` -You also need docker, either by installing the `docker.io` package, or by installing `docker-ce` by following [these instructions for Ubuntu](https://docs.docker.com/install/linux/docker-ce/ubuntu/) or [for Debian](https://docs.docker.com/install/linux/docker-ce/debian/), or installing the [Docker snap package](https://snapcraft.io/docker). +You also need docker, either by installing the [Docker snap package](https://snapcraft.io/docker), installing the `docker.io` package, or by installing `docker-ce` by following [these instructions for Ubuntu](https://docs.docker.com/install/linux/docker-ce/ubuntu/) or [for Debian](https://docs.docker.com/install/linux/docker-ce/debian/). Run from source tree: diff --git a/stdeb.cfg b/stdeb.cfg index 78eb225..9c981c3 100644 --- a/stdeb.cfg +++ b/stdeb.cfg @@ -1,6 +1,6 @@ [DEFAULT] Package3: dangerzone -Depends3: docker.io | docker-ce, python3, python3-pyqt5, python3-appdirs, python3-click, python3-xdg, python3-requests, python3-termcolor -Build-Depends: python3, python3-all +Depends3: python3, python3-pyside2.qtcore python3-pyside2.qtgui python3-pyside2.qtwidgets, python3-appdirs, python3-click, python3-xdg, python3-requests, python3-termcolor +Build-Depends: dh-python, python3, python3-all Suite: bionic X-Python3-Version: >= 3.6 \ No newline at end of file From 11d0c6c88f72fbea631f2baabb355a4ba989bb5d Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Mon, 26 Oct 2020 17:04:14 -0700 Subject: [PATCH 5/9] Update poetry deps and build instructions for macOS --- BUILD.md | 4 +- poetry.lock | 364 ++++++++++++++----------------------------------- pyproject.toml | 15 +- 3 files changed, 111 insertions(+), 272 deletions(-) diff --git a/BUILD.md b/BUILD.md index 9d60a67..ed6ca69 100644 --- a/BUILD.md +++ b/BUILD.md @@ -46,9 +46,7 @@ Create a .rpm: ## macOS -Install Xcode from the Mac App Store. Once it's installed, run it for the first time to set it up. Also, run this to make sure command line tools are installed: `xcode-select --install`. And finally, open Xcode, go to Preferences > Locations, and make sure under Command Line Tools you select an installed version from the dropdown. (This is required for installing Qt5.) - -Download and install Python 3.7.4 from https://www.python.org/downloads/release/python-374/. I downloaded `python-3.7.4-macosx10.9.pkg`. +Download and install Python 3.9.0 from https://www.python.org/downloads/release/python-390/. I downloaded `python-3.9.0-macosx10.9.pkg`. Install Qt 5.14.0 for macOS from https://www.qt.io/offline-installers. I downloaded `qt-opensource-mac-x64-5.14.0.dmg`. In the installer, you can skip making an account, and all you need is `Qt` > `Qt 5.14.0` > `macOS`. diff --git a/poetry.lock b/poetry.lock index 3eee0d9..3f76fe3 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,239 +1,171 @@ [[package]] -category = "main" -description = "Python graph (network) package" name = "altgraph" -optional = false -python-versions = "*" version = "0.17" +description = "Python graph (network) package" +category = "main" +optional = false +python-versions = "*" [[package]] -category = "main" -description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." name = "appdirs" -optional = false -python-versions = "*" version = "1.4.4" - -[[package]] -category = "dev" -description = "Classes Without Boilerplate" -name = "attrs" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "20.2.0" - -[package.extras] -dev = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "sphinx-rtd-theme", "pre-commit"] -docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"] -tests = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] -tests_no_zope = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] - -[[package]] -category = "dev" -description = "The uncompromising code formatter." -name = "black" -optional = false -python-versions = ">=3.6" -version = "19.10b0" - -[package.dependencies] -appdirs = "*" -attrs = ">=18.1.0" -click = ">=6.5" -pathspec = ">=0.6,<1" -regex = "*" -toml = ">=0.9.4" -typed-ast = ">=1.4.0" - -[package.extras] -d = ["aiohttp (>=3.3.2)", "aiohttp-cors"] - -[[package]] +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "main" -description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = "*" + +[[package]] name = "certifi" -optional = false -python-versions = "*" version = "2020.6.20" - -[[package]] +description = "Python package for providing Mozilla's CA Bundle." category = "main" -description = "Universal encoding detector for Python 2 and 3" -name = "chardet" optional = false python-versions = "*" -version = "3.0.4" [[package]] +name = "chardet" +version = "3.0.4" +description = "Universal encoding detector for Python 2 and 3" category = "main" -description = "Composable command line interface toolkit" +optional = false +python-versions = "*" + +[[package]] name = "click" +version = "7.1.2" +description = "Composable command line interface toolkit" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "7.1.2" [[package]] -category = "dev" -description = "Python 2.7 backport of the \"dis\" module from Python 3.5+" -marker = "sys_platform == \"darwin\"" name = "dis3" +version = "0.1.3" +description = "Python 2.7 backport of the \"dis\" module from Python 3.5+" +category = "dev" optional = false python-versions = "*" -version = "0.1.3" [[package]] -category = "main" -description = "Internationalized Domain Names in Applications (IDNA)" name = "idna" +version = "2.10" +description = "Internationalized Domain Names in Applications (IDNA)" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.10" [[package]] -category = "main" -description = "Mach-O header analysis and editing" name = "macholib" +version = "1.14" +description = "Mach-O header analysis and editing" +category = "main" optional = false python-versions = "*" -version = "1.14" [package.dependencies] altgraph = ">=0.15" [[package]] -category = "dev" -description = "Utility library for gitignore style pattern matching of file paths." -name = "pathspec" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "0.8.0" - -[[package]] -category = "dev" -description = "PyInstaller bundles a Python application and all its dependencies into a single package." -marker = "sys_platform == \"darwin\"" name = "pyinstaller" +version = "3.6" +description = "PyInstaller bundles a Python application and all its dependencies into a single package." +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "3.6" [package.dependencies] altgraph = "*" dis3 = "*" -setuptools = "*" [[package]] -category = "main" -description = "Python<->ObjC Interoperability Module" -marker = "sys_platform == \"darwin\"" name = "pyobjc-core" +version = "6.2.2" +description = "Python<->ObjC Interoperability Module" +category = "main" optional = false python-versions = ">=3.6" -version = "6.2.2" [[package]] -category = "main" -description = "Wrappers for the Cocoa frameworks on macOS" -marker = "sys_platform == \"darwin\"" name = "pyobjc-framework-cocoa" +version = "6.2.2" +description = "Wrappers for the Cocoa frameworks on macOS" +category = "main" optional = false python-versions = ">=3.6" -version = "6.2.2" [package.dependencies] pyobjc-core = ">=6.2.2" [[package]] -category = "main" -description = "Wrappers for the framework CoreServices on macOS" -marker = "sys_platform == \"darwin\"" name = "pyobjc-framework-coreservices" +version = "6.2.2" +description = "Wrappers for the framework CoreServices on macOS" +category = "main" optional = false python-versions = ">=3.6" -version = "6.2.2" [package.dependencies] pyobjc-core = ">=6.2.2" pyobjc-framework-FSEvents = ">=6.2.2" [[package]] -category = "main" -description = "Wrappers for the framework FSEvents on macOS" -marker = "sys_platform == \"darwin\"" name = "pyobjc-framework-fsevents" +version = "6.2.2" +description = "Wrappers for the framework FSEvents on macOS" +category = "main" optional = false python-versions = ">=3.6" -version = "6.2.2" [package.dependencies] pyobjc-core = ">=6.2.2" pyobjc-framework-Cocoa = ">=6.2.2" [[package]] -category = "main" -description = "Wrappers for the framework LaunchServices on macOS" -marker = "sys_platform == \"darwin\"" name = "pyobjc-framework-launchservices" +version = "6.2.2" +description = "Wrappers for the framework LaunchServices on macOS" +category = "main" optional = false python-versions = ">=3.6" -version = "6.2.2" [package.dependencies] pyobjc-core = ">=6.2.2" pyobjc-framework-CoreServices = ">=6.2.2" [[package]] -category = "main" -description = "Python bindings for the Qt cross platform application toolkit" -name = "pyqt5" -optional = false -python-versions = ">=3.5" +name = "pyside2" version = "5.15.1" +description = "Python bindings for the Qt cross-platform application and UI framework" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <3.10" [package.dependencies] -PyQt5-sip = ">=12.8,<13" +shiboken2 = "5.15.1" [[package]] -category = "main" -description = "The sip module support for PyQt5" -name = "pyqt5-sip" -optional = false -python-versions = ">=3.5" -version = "12.8.1" - -[[package]] -category = "main" -description = "Python for Window Extensions" -marker = "sys_platform == \"windows\"" name = "pywin32" -optional = false -python-versions = "*" version = "227" +description = "Python for Window Extensions" +category = "main" +optional = false +python-versions = "*" [[package]] -category = "main" -description = "PyXDG contains implementations of freedesktop.org standards in python." -marker = "sys_platform == \"linux\"" name = "pyxdg" -optional = false -python-versions = "*" version = "0.26" - -[[package]] -category = "dev" -description = "Alternative regular expression module, to replace re." -name = "regex" +description = "PyXDG contains implementations of freedesktop.org standards in python." +category = "main" optional = false python-versions = "*" -version = "2020.10.11" [[package]] -category = "main" -description = "Python HTTP for Humans." name = "requests" +version = "2.24.0" +description = "Python HTTP for Humans." +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "2.24.0" [package.dependencies] certifi = ">=2017.4.17" @@ -243,53 +175,44 @@ urllib3 = ">=1.21.1,<1.25.0 || >1.25.0,<1.25.1 || >1.25.1,<1.26" [package.extras] security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] -socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7)", "win-inet-pton"] +socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] [[package]] +name = "shiboken2" +version = "5.15.1" +description = "Python / C++ bindings helper module" category = "main" -description = "ANSII Color formatting for output in terminal." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <3.10" + +[[package]] name = "termcolor" -optional = false -python-versions = "*" version = "1.1.0" - -[[package]] -category = "dev" -description = "Python Library for Tom's Obvious, Minimal Language" -name = "toml" -optional = false -python-versions = "*" -version = "0.10.1" - -[[package]] -category = "dev" -description = "a fork of Python 2 and 3 ast modules with type comment support" -name = "typed-ast" -optional = false -python-versions = "*" -version = "1.4.1" - -[[package]] +description = "ANSII Color formatting for output in terminal." category = "main" -description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = "*" + +[[package]] name = "urllib3" +version = "1.25.11" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" -version = "1.25.10" [package.extras] brotli = ["brotlipy (>=0.6.0)"] -secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "pyOpenSSL (>=0.14)", "ipaddress"] -socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"] +secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] -category = "main" -description = "Windows Management Instrumentation" -marker = "sys_platform == \"windows\"" name = "wmi" +version = "1.5.1" +description = "Windows Management Instrumentation" +category = "main" optional = false python-versions = "*" -version = "1.5.1" [package.dependencies] pywin32 = "*" @@ -302,8 +225,9 @@ package = ["wheel", "twine"] tests = ["pytest"] [metadata] -content-hash = "d35932b9017d8a287c8c33bc3c7086ce46679c0165aace5a4aa9fd5f506d04fd" -python-versions = "^3.7" +lock-version = "1.1" +python-versions = ">=3.7,<3.10" +content-hash = "21cab7363f119ab648f232ee2ae19b64e8113aede19e67da58c65818e71e90c0" [metadata.files] altgraph = [ @@ -314,14 +238,6 @@ appdirs = [ {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, ] -attrs = [ - {file = "attrs-20.2.0-py2.py3-none-any.whl", hash = "sha256:fce7fc47dfc976152e82d53ff92fa0407700c21acd20886a13777a0d20e655dc"}, - {file = "attrs-20.2.0.tar.gz", hash = "sha256:26b54ddbbb9ee1d34d5d3668dd37d6cf74990ab23c828c2888dccdceee395594"}, -] -black = [ - {file = "black-19.10b0-py36-none-any.whl", hash = "sha256:1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b"}, - {file = "black-19.10b0.tar.gz", hash = "sha256:c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539"}, -] certifi = [ {file = "certifi-2020.6.20-py2.py3-none-any.whl", hash = "sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41"}, {file = "certifi-2020.6.20.tar.gz", hash = "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3"}, @@ -347,10 +263,6 @@ macholib = [ {file = "macholib-1.14-py2.py3-none-any.whl", hash = "sha256:c500f02867515e6c60a27875b408920d18332ddf96b4035ef03beddd782d4281"}, {file = "macholib-1.14.tar.gz", hash = "sha256:0c436bc847e7b1d9bda0560351bf76d7caf930fb585a828d13608839ef42c432"}, ] -pathspec = [ - {file = "pathspec-0.8.0-py2.py3-none-any.whl", hash = "sha256:7d91249d21749788d07a2d0f94147accd8f845507400749ea19c1ec9054a12b0"}, - {file = "pathspec-0.8.0.tar.gz", hash = "sha256:da45173eb3a6f2a5a487efba21f050af2b41948be6ab52b6a1e3ff22bb8b7061"}, -] pyinstaller = [ {file = "PyInstaller-3.6.tar.gz", hash = "sha256:3730fa80d088f8bb7084d32480eb87cbb4ddb64123363763cf8f2a1378c1c4b7"}, ] @@ -380,35 +292,13 @@ pyobjc-framework-launchservices = [ {file = "pyobjc-framework-LaunchServices-6.2.2.tar.gz", hash = "sha256:d9c2ae16a113adaa5b8a86481402a6dceb381c1419d33bf5b98fa615975beda2"}, {file = "pyobjc_framework_LaunchServices-6.2.2-py2.py3-none-any.whl", hash = "sha256:edc09a001f343b459c130a8518e18b9b7b5006428e152d4dc711e52d5ad76b12"}, ] -pyqt5 = [ - {file = "PyQt5-5.15.1-5.15.1-cp35.cp36.cp37.cp38.cp39-abi3-macosx_10_13_intel.whl", hash = "sha256:b9e7cc3ec69f80834f3f7507478c77e4d42411d5e9e557350e61b2660d12abc2"}, - {file = "PyQt5-5.15.1-5.15.1-cp35.cp36.cp37.cp38.cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:b1ea7e82004dc7b311d1e29df2f276461016e2d180e10c73805ace4376125ed9"}, - {file = "PyQt5-5.15.1-5.15.1-cp35.cp36.cp37.cp38.cp39-none-win32.whl", hash = "sha256:4e47021c2b8e89a3bc64247dfb224144e5c8d77e3ab44f3842d120aab6b3cbd4"}, - {file = "PyQt5-5.15.1-5.15.1-cp35.cp36.cp37.cp38.cp39-none-win_amd64.whl", hash = "sha256:17a6d5258796bae16e447aa3efa00258425c09cf88ef68238762628a5dde7c6f"}, - {file = "PyQt5-5.15.1.tar.gz", hash = "sha256:d9a76b850246d08da9863189ecb98f6c2aa9b4d97a3e85e29330a264aed0f9a1"}, -] -pyqt5-sip = [ - {file = "PyQt5_sip-12.8.1-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:bb5a87b66fc1445915104ee97f7a20a69decb42f52803e3b0795fa17ff88226c"}, - {file = "PyQt5_sip-12.8.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:a29e2ac399429d3b7738f73e9081e50783e61ac5d29344e0802d0dcd6056c5a2"}, - {file = "PyQt5_sip-12.8.1-cp35-cp35m-win32.whl", hash = "sha256:0304ca9114b9817a270f67f421355075b78ff9fc25ac58ffd72c2601109d2194"}, - {file = "PyQt5_sip-12.8.1-cp35-cp35m-win_amd64.whl", hash = "sha256:84ba7746762bd223bed22428e8561aa267a229c28344c2d28c5d5d3f8970cffb"}, - {file = "PyQt5_sip-12.8.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:7b81382ce188d63890a0e35abe0f9bb946cabc873a31873b73583b0fc84ac115"}, - {file = "PyQt5_sip-12.8.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:b6d42250baec52a5f77de64e2951d001c5501c3a2df2179f625b241cbaec3369"}, - {file = "PyQt5_sip-12.8.1-cp36-cp36m-win32.whl", hash = "sha256:6c1ebee60f1d2b3c70aff866b7933d8d8d7646011f7c32f9321ee88c290aa4f9"}, - {file = "PyQt5_sip-12.8.1-cp36-cp36m-win_amd64.whl", hash = "sha256:34dcd29be47553d5f016ff86e89e24cbc5eebae92eb2f96fb32d2d7ba028c43c"}, - {file = "PyQt5_sip-12.8.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:ed897c58acf4a3cdca61469daa31fe6e44c33c6c06a37c3f21fab31780b3b86a"}, - {file = "PyQt5_sip-12.8.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:a1b8ef013086e224b8e86c93f880f776d01b59195bdfa2a8e0b23f0480678fec"}, - {file = "PyQt5_sip-12.8.1-cp37-cp37m-win32.whl", hash = "sha256:0cd969be528c27bbd4755bd323dff4a79a8fdda28215364e6ce3e069cb56c2a9"}, - {file = "PyQt5_sip-12.8.1-cp37-cp37m-win_amd64.whl", hash = "sha256:c9800729badcb247765e4ffe2241549d02da1fa435b9db224845bc37c3e99cb0"}, - {file = "PyQt5_sip-12.8.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9312ec47cac4e33c11503bc1cbeeb0bdae619620472f38e2078c5a51020a930f"}, - {file = "PyQt5_sip-12.8.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2f35e82fd7ec1e1f6716e9154721c7594956a4f5bd4f826d8c6a6453833cc2f0"}, - {file = "PyQt5_sip-12.8.1-cp38-cp38-win32.whl", hash = "sha256:da9c9f1e65b9d09e73bd75befc82961b6b61b5a3b9d0a7c832168e1415f163c6"}, - {file = "PyQt5_sip-12.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:832fd60a264de4134c2824d393320838f3ab648180c9c357ec58a74524d24507"}, - {file = "PyQt5_sip-12.8.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c317ab1263e6417c498b81f5c970a9b1af7acefab1f80b4cc0f2f8e661f29fc5"}, - {file = "PyQt5_sip-12.8.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:c9d6d448c29dc6606bb7974696608f81f4316c8234f7c7216396ed110075e777"}, - {file = "PyQt5_sip-12.8.1-cp39-cp39-win32.whl", hash = "sha256:5a011aeff89660622a6d5c3388d55a9d76932f3b82c95e82fc31abd8b1d2990d"}, - {file = "PyQt5_sip-12.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:f168f0a7f32b81bfeffdf003c36f25d81c97dee5eb67072a5183e761fe250f13"}, - {file = "PyQt5_sip-12.8.1.tar.gz", hash = "sha256:30e944db9abee9cc757aea16906d4198129558533eb7fadbe48c5da2bd18e0bd"}, +pyside2 = [ + {file = "PySide2-5.15.1-5.15.1-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:9d7c076d1c4665c57a7e0b912a52be132410d369c98325c0583c323f10cbe3aa"}, + {file = "PySide2-5.15.1-5.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:66cc78e4c6b0754409c79a3c0321a87728d1ef2cc137c61737f1cc1b24574988"}, + {file = "PySide2-5.15.1-5.15.1-cp35.cp36.cp37.cp38.cp39-abi3-macosx_10_13_intel.whl", hash = "sha256:8b737c2f42770918623e704d1bef9cd3df39bd09f1bc61cc550bdc6daa7088f6"}, + {file = "PySide2-5.15.1-5.15.1-cp35.cp36.cp37.cp38.cp39-abi3-manylinux1_x86_64.whl", hash = "sha256:76f0e0875ed9eb526a98b9e8dedac033a25cdcf7a51eb366451a0202b140d8d4"}, + {file = "PySide2-5.15.1-5.15.1-cp35.cp36.cp37.cp38.cp39-none-win32.whl", hash = "sha256:db7ae55f88a13fda43ed956a12853f8b5e6ae7148f9ac3565719afa03bbeca8e"}, + {file = "PySide2-5.15.1-5.15.1-cp35.cp36.cp37.cp38.cp39-none-win_amd64.whl", hash = "sha256:3c9a24557edf25b60fded6ed99a9b5e4b287be1cc3857e76e18dd930e54240e3"}, ] pywin32 = [ {file = "pywin32-227-cp27-cp27m-win32.whl", hash = "sha256:371fcc39416d736401f0274dd64c2302728c9e034808e37381b5e1b22be4a6b0"}, @@ -428,72 +318,24 @@ pyxdg = [ {file = "pyxdg-0.26-py2.py3-none-any.whl", hash = "sha256:1948ff8e2db02156c0cccd2529b43c0cff56ebaa71f5f021bbd755bc1419190e"}, {file = "pyxdg-0.26.tar.gz", hash = "sha256:fe2928d3f532ed32b39c32a482b54136fe766d19936afc96c8f00645f9da1a06"}, ] -regex = [ - {file = "regex-2020.10.11-cp27-cp27m-win32.whl", hash = "sha256:4f5c0fe46fb79a7adf766b365cae56cafbf352c27358fda811e4a1dc8216d0db"}, - {file = "regex-2020.10.11-cp27-cp27m-win_amd64.whl", hash = "sha256:39a5ef30bca911f5a8a3d4476f5713ed4d66e313d9fb6755b32bec8a2e519635"}, - {file = "regex-2020.10.11-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:7c4fc5a8ec91a2254bb459db27dbd9e16bba1dabff638f425d736888d34aaefa"}, - {file = "regex-2020.10.11-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d537e270b3e6bfaea4f49eaf267984bfb3628c86670e9ad2a257358d3b8f0955"}, - {file = "regex-2020.10.11-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:a8240df4957a5b0e641998a5d78b3c4ea762c845d8cb8997bf820626826fde9a"}, - {file = "regex-2020.10.11-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:4302153abb96859beb2c778cc4662607a34175065fc2f33a21f49eb3fbd1ccd3"}, - {file = "regex-2020.10.11-cp36-cp36m-win32.whl", hash = "sha256:c077c9d04a040dba001cf62b3aff08fd85be86bccf2c51a770c77377662a2d55"}, - {file = "regex-2020.10.11-cp36-cp36m-win_amd64.whl", hash = "sha256:46ab6070b0d2cb85700b8863b3f5504c7f75d8af44289e9562195fe02a8dd72d"}, - {file = "regex-2020.10.11-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:d629d750ebe75a88184db98f759633b0a7772c2e6f4da529f0027b4a402c0e2f"}, - {file = "regex-2020.10.11-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:8e7ef296b84d44425760fe813cabd7afbb48c8dd62023018b338bbd9d7d6f2f0"}, - {file = "regex-2020.10.11-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:e490f08897cb44e54bddf5c6e27deca9b58c4076849f32aaa7a0b9f1730f2c20"}, - {file = "regex-2020.10.11-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:850339226aa4fec04916386577674bb9d69abe0048f5d1a99f91b0004bfdcc01"}, - {file = "regex-2020.10.11-cp37-cp37m-win32.whl", hash = "sha256:60c4f64d9a326fe48e8738c3dbc068e1edc41ff7895a9e3723840deec4bc1c28"}, - {file = "regex-2020.10.11-cp37-cp37m-win_amd64.whl", hash = "sha256:8ba3efdd60bfee1aa784dbcea175eb442d059b576934c9d099e381e5a9f48930"}, - {file = "regex-2020.10.11-cp38-cp38-manylinux1_i686.whl", hash = "sha256:2308491b3e6c530a3bb38a8a4bb1dc5fd32cbf1e11ca623f2172ba17a81acef1"}, - {file = "regex-2020.10.11-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:b8806649983a1c78874ec7e04393ef076805740f6319e87a56f91f1767960212"}, - {file = "regex-2020.10.11-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:a2a31ee8a354fa3036d12804730e1e20d58bc4e250365ead34b9c30bbe9908c3"}, - {file = "regex-2020.10.11-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:d9d53518eeed12190744d366ec4a3f39b99d7daa705abca95f87dd8b442df4ad"}, - {file = "regex-2020.10.11-cp38-cp38-win32.whl", hash = "sha256:3d5a8d007116021cf65355ada47bf405656c4b3b9a988493d26688275fde1f1c"}, - {file = "regex-2020.10.11-cp38-cp38-win_amd64.whl", hash = "sha256:f579caecbbca291b0fcc7d473664c8c08635da2f9b1567c22ea32311c86ef68c"}, - {file = "regex-2020.10.11-cp39-cp39-manylinux1_i686.whl", hash = "sha256:8c8c42aa5d3ac9a49829c4b28a81bebfa0378996f9e0ca5b5ab8a36870c3e5ee"}, - {file = "regex-2020.10.11-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:c529ba90c1775697a65b46c83d47a2d3de70f24d96da5d41d05a761c73b063af"}, - {file = "regex-2020.10.11-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:6cf527ec2f3565248408b61dd36e380d799c2a1047eab04e13a2b0c15dd9c767"}, - {file = "regex-2020.10.11-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:671c51d352cfb146e48baee82b1ee8d6ffe357c292f5e13300cdc5c00867ebfc"}, - {file = "regex-2020.10.11-cp39-cp39-win32.whl", hash = "sha256:a63907332531a499b8cdfd18953febb5a4c525e9e7ca4ac147423b917244b260"}, - {file = "regex-2020.10.11-cp39-cp39-win_amd64.whl", hash = "sha256:1a16afbfadaadc1397353f9b32e19a65dc1d1804c80ad73a14f435348ca017ad"}, - {file = "regex-2020.10.11.tar.gz", hash = "sha256:463e770c48da76a8da82b8d4a48a541f314e0df91cbb6d873a341dbe578efafd"}, -] requests = [ {file = "requests-2.24.0-py2.py3-none-any.whl", hash = "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898"}, {file = "requests-2.24.0.tar.gz", hash = "sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b"}, ] +shiboken2 = [ + {file = "shiboken2-5.15.1-5.15.1-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:610e3fd0cd16e85f85ef81bc09762868ade2239d43f6de6f3db0733ee6810619"}, + {file = "shiboken2-5.15.1-5.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:28f98204d0ad77861b553db12eec0fa04c6e2da7e16126e761bdd70bbd8ae511"}, + {file = "shiboken2-5.15.1-5.15.1-cp35.cp36.cp37.cp38.cp39-abi3-macosx_10_13_intel.whl", hash = "sha256:44d0cecf0b0b5d844d7cb1edccc209cb9cd26f2c1624298af9905bb41782fbbf"}, + {file = "shiboken2-5.15.1-5.15.1-cp35.cp36.cp37.cp38.cp39-abi3-manylinux1_x86_64.whl", hash = "sha256:71f563daabc3a363ccc27a843cfb452f01ebaeb24e5e46704964ffa4c7dc98d9"}, + {file = "shiboken2-5.15.1-5.15.1-cp35.cp36.cp37.cp38.cp39-none-win32.whl", hash = "sha256:4c112b5758a39ffa5473d2c6995e2594eb6e002332d9dac35e2efd9debf157a2"}, + {file = "shiboken2-5.15.1-5.15.1-cp35.cp36.cp37.cp38.cp39-none-win_amd64.whl", hash = "sha256:55249cad55541471b60256179d92be08d520873b76f9cff595bae775dbb06aba"}, +] termcolor = [ {file = "termcolor-1.1.0.tar.gz", hash = "sha256:1d6d69ce66211143803fbc56652b41d73b4a400a2891d7bf7a1cdf4c02de613b"}, ] -toml = [ - {file = "toml-0.10.1-py2.py3-none-any.whl", hash = "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88"}, - {file = "toml-0.10.1.tar.gz", hash = "sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f"}, -] -typed-ast = [ - {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3"}, - {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb"}, - {file = "typed_ast-1.4.1-cp35-cp35m-win32.whl", hash = "sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919"}, - {file = "typed_ast-1.4.1-cp35-cp35m-win_amd64.whl", hash = "sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01"}, - {file = "typed_ast-1.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75"}, - {file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652"}, - {file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7"}, - {file = "typed_ast-1.4.1-cp36-cp36m-win32.whl", hash = "sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1"}, - {file = "typed_ast-1.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa"}, - {file = "typed_ast-1.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614"}, - {file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41"}, - {file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b"}, - {file = "typed_ast-1.4.1-cp37-cp37m-win32.whl", hash = "sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe"}, - {file = "typed_ast-1.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355"}, - {file = "typed_ast-1.4.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6"}, - {file = "typed_ast-1.4.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907"}, - {file = "typed_ast-1.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d"}, - {file = "typed_ast-1.4.1-cp38-cp38-win32.whl", hash = "sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c"}, - {file = "typed_ast-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4"}, - {file = "typed_ast-1.4.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34"}, - {file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"}, -] urllib3 = [ - {file = "urllib3-1.25.10-py2.py3-none-any.whl", hash = "sha256:e7983572181f5e1522d9c98453462384ee92a0be7fac5f1413a1e35c56cc0461"}, - {file = "urllib3-1.25.10.tar.gz", hash = "sha256:91056c15fa70756691db97756772bb1eb9678fa585d9184f24534b100dc60f4a"}, + {file = "urllib3-1.25.11-py2.py3-none-any.whl", hash = "sha256:f5321fbe4bf3fefa0efd0bfe7fb14e90909eb62a48ccda331726b4319897dd5e"}, + {file = "urllib3-1.25.11.tar.gz", hash = "sha256:8d7eaa5a82a1cac232164990f04874c594c9453ec55eef02eab885aa02fc17a2"}, ] wmi = [ {file = "WMI-1.5.1-py2.py3-none-any.whl", hash = "sha256:1d6b085e5c445141c475476000b661f60fff1aaa19f76bf82b7abb92e0ff4942"}, diff --git a/pyproject.toml b/pyproject.toml index b8cd7f1..21e7cf1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,21 +6,20 @@ authors = ["Micah Lee "] license = "MIT" [tool.poetry.dependencies] -python = "^3.7" -PyQt5 = "^5.14.1" +python = ">=3.7,<3.10" click = "^7.0" appdirs = "^1.4.3" requests = "^2.22.0" +macholib = "^1.14" +termcolor = "^1.1.0" +PySide2 = "^5.15.1" +pywin32 = {version = "^227", platform = "windows"} +wmi = {version = "^1.4.9", platform = "windows"} pyxdg = {version = "^0.26", platform = "linux"} pyobjc-core = {version = "^6.1", platform = "darwin"} pyobjc-framework-launchservices = {version = "^6.1", platform = "darwin"} -macholib = "^1.14" -pywin32 = {version = "^227", platform = "windows"} -wmi = {version = "^1.4.9", platform = "windows"} -termcolor = "^1.1.0" [tool.poetry.dev-dependencies] -black = "^19.10b0" pyinstaller = {version = "^3.6", platform = "darwin"} setuptools = {version = "^45.2.0", platform = "windows"} @@ -28,5 +27,5 @@ setuptools = {version = "^45.2.0", platform = "windows"} dangerzone = 'dangerzone:main' [build-system] -requires = ["poetry>=0.12"] +requires = ["poetry>=1.1.4"] build-backend = "poetry.masonry.api" From 269cf5b431ad556c78231f6aae02298f1716dc02 Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Tue, 27 Oct 2020 11:55:21 -0700 Subject: [PATCH 6/9] Add Windows changes --- BUILD.md | 10 ++--- dangerzone/docker_installer.py | 28 ++++++++++++- poetry.lock | 72 ++++++++++++++++++---------------- pyproject.toml | 24 ++++++------ 4 files changed, 80 insertions(+), 54 deletions(-) diff --git a/BUILD.md b/BUILD.md index ed6ca69..b938443 100644 --- a/BUILD.md +++ b/BUILD.md @@ -59,7 +59,7 @@ poetry install Run from source tree: ``` -poetry run ./dev_scripts/dangerzone +poetry run dangerzone ``` To create an app bundle and DMG for distribution, use the `build_app.py` script @@ -87,9 +87,7 @@ The output is in the `dist` folder. These instructions include adding folders to the path in Windows. To do this, go to Start and type "advanced system settings", and open "View advanced system settings" in the Control Panel. Click Environment Variables. Under "System variables" double-click on Path. From there you can add and remove folders that are available in the PATH. -Download Python 3.7.6, 32-bit (x86) from https://www.python.org/downloads/release/python-376/. I downloaded python-3.7.6.exe. When installing it, make sure to check the "Add Python 3.7 to PATH" checkbox on the first page of the installer. - -Install the Qt 5.14.1 from https://www.qt.io/offline-installers. I downloaded qt-opensource-windows-x86-5.14.1.exe. In the installer, unfortunately you have login to an account. Then all you need `Qt` > `Qt 5.14.1` > `MSVC 2017 32-bit`. +Download Python 3.9.0, 32-bit (x86) from https://www.python.org/downloads/release/python-390/. I downloaded python-3.9.0.exe. When installing it, make sure to check the "Add Python 3.9 to PATH" checkbox on the first page of the installer. Install [poetry](https://python-poetry.org/). Open PowerShell, and run: @@ -97,7 +95,7 @@ Install [poetry](https://python-poetry.org/). Open PowerShell, and run: (Invoke-WebRequest -Uri https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py -UseBasicParsing).Content | python ``` -And add `%USERPROFILE%\.poetry\bin` to your path. Then open a command prompt and cd to the `dangerzone` folder, and install the poetry dependencies: +Change to the `dangerzone` folder, and install the poetry dependencies: ``` poetry install @@ -106,7 +104,7 @@ poetry install After that you can launch dangerzone during development with: ``` -poetry run python dev_scripts\dangerzone +poetry run dangerzone ``` ### If you want to build a .exe diff --git a/dangerzone/docker_installer.py b/dangerzone/docker_installer.py index 6398631..3619ef1 100644 --- a/dangerzone/docker_installer.py +++ b/dangerzone/docker_installer.py @@ -61,7 +61,7 @@ class DockerInstaller(QtWidgets.QDialog): self.setWindowTitle("dangerzone") self.setWindowIcon(self.global_common.get_window_icon()) - self.setMinimumHeight(170) + # self.setMinimumHeight(170) label = QtWidgets.QLabel() if platform.system() == "Darwin": @@ -90,9 +90,13 @@ class DockerInstaller(QtWidgets.QDialog): self.cancel_button = QtWidgets.QPushButton("Cancel") self.cancel_button.clicked.connect(self.cancel_clicked) + self.ok_button = QtWidgets.QPushButton("OK") + self.ok_button.clicked.connect(self.ok_clicked) + buttons_layout = QtWidgets.QHBoxLayout() buttons_layout.addStretch() buttons_layout.addWidget(self.open_finder_button) + buttons_layout.addWidget(self.ok_button) buttons_layout.addWidget(self.cancel_button) buttons_layout.addStretch() @@ -163,6 +167,16 @@ class DockerInstaller(QtWidgets.QDialog): except: pass + def ok_clicked(self): + self.accept() + + if self.download_t: + self.download_t.quit() + try: + os.remove(self.installer_filename) + except: + pass + def open_finder_clicked(self): if platform.system() == "Darwin": subprocess.call(["open", "-R", self.open_finder_path]) @@ -179,12 +193,22 @@ class DockerInstaller(QtWidgets.QDialog): docker_app_path = "C:\\Program Files\\Docker\\Docker\\Docker Desktop.exe" if not os.path.exists(docker_app_path): - self.download() + if platform.system() == "Windows": + self.task_label.setText( + "Download Docker, install it, and then run Dangerzone again." + ) + self.task_label.setTextFormat(QtCore.Qt.RichText) + self.progress.hide() + self.cancel_button.hide() + else: + self.ok_button.hide() + self.download() else: self.task_label.setText( "Docker is installed, but you must launch it first. Open Docker, make sure it's running, and then open Dangerzone again." ) self.progress.hide() + self.ok_button.hide() self.cancel_button.hide() self.open_finder_path = docker_app_path diff --git a/poetry.lock b/poetry.lock index 3f76fe3..9e5093d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -38,14 +38,6 @@ category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -[[package]] -name = "dis3" -version = "0.1.3" -description = "Python 2.7 backport of the \"dis\" module from Python 3.5+" -category = "dev" -optional = false -python-versions = "*" - [[package]] name = "idna" version = "2.10" @@ -67,15 +59,28 @@ altgraph = ">=0.15" [[package]] name = "pyinstaller" -version = "3.6" +version = "4.0" description = "PyInstaller bundles a Python application and all its dependencies into a single package." category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = "*" [package.dependencies] altgraph = "*" -dis3 = "*" +macholib = {version = ">=1.8", markers = "sys_platform == \"darwin\""} +pyinstaller-hooks-contrib = ">=2020.6" + +[package.extras] +encryption = ["tinyaes (>=1.0.0)"] +hook_testing = ["pytest (>=2.7.3)", "execnet (>=1.5.0)", "psutil"] + +[[package]] +name = "pyinstaller-hooks-contrib" +version = "2020.9" +description = "Community maintained hooks for PyInstaller" +category = "dev" +optional = false +python-versions = "*" [[package]] name = "pyobjc-core" @@ -145,7 +150,7 @@ shiboken2 = "5.15.1" [[package]] name = "pywin32" -version = "227" +version = "228" description = "Python for Window Extensions" category = "main" optional = false @@ -153,7 +158,7 @@ python-versions = "*" [[package]] name = "pyxdg" -version = "0.26" +version = "0.27" description = "PyXDG contains implementations of freedesktop.org standards in python." category = "main" optional = false @@ -227,7 +232,7 @@ tests = ["pytest"] [metadata] lock-version = "1.1" python-versions = ">=3.7,<3.10" -content-hash = "21cab7363f119ab648f232ee2ae19b64e8113aede19e67da58c65818e71e90c0" +content-hash = "dd8ed673b0bfda46b5c4ff39858b7a33dcdeb16fa0fd872c169c0176695c9a12" [metadata.files] altgraph = [ @@ -250,11 +255,6 @@ click = [ {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, ] -dis3 = [ - {file = "dis3-0.1.3-py2-none-any.whl", hash = "sha256:61f7720dd0d8749d23fda3d7227ce74d73da11c2fade993a67ab2f9852451b14"}, - {file = "dis3-0.1.3-py3-none-any.whl", hash = "sha256:30b6412d33d738663e8ded781b138f4b01116437f0872aa56aa3adba6aeff218"}, - {file = "dis3-0.1.3.tar.gz", hash = "sha256:9259b881fc1df02ed12ac25f82d4a85b44241854330b1a651e40e0c675cb2d1e"}, -] idna = [ {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, @@ -264,7 +264,11 @@ macholib = [ {file = "macholib-1.14.tar.gz", hash = "sha256:0c436bc847e7b1d9bda0560351bf76d7caf930fb585a828d13608839ef42c432"}, ] pyinstaller = [ - {file = "PyInstaller-3.6.tar.gz", hash = "sha256:3730fa80d088f8bb7084d32480eb87cbb4ddb64123363763cf8f2a1378c1c4b7"}, + {file = "pyinstaller-4.0.tar.gz", hash = "sha256:970beb07115761d5e4ec317c1351b712fd90ae7f23994db914c633281f99bab0"}, +] +pyinstaller-hooks-contrib = [ + {file = "pyinstaller-hooks-contrib-2020.9.tar.gz", hash = "sha256:a5fd45a920012802e3f2089e1d3501ef2f49265dfea8fc46c3310f18e3326c91"}, + {file = "pyinstaller_hooks_contrib-2020.9-py2.py3-none-any.whl", hash = "sha256:c382f3ac1a42b45cfecd581475c36db77da90e479b2f5bcb6d840d21fa545114"}, ] pyobjc-core = [ {file = "pyobjc-core-6.2.2.tar.gz", hash = "sha256:38e7b15a042439dadd18b28b78229e52fb882460fc16ddbae342b9972d5a827c"}, @@ -301,22 +305,22 @@ pyside2 = [ {file = "PySide2-5.15.1-5.15.1-cp35.cp36.cp37.cp38.cp39-none-win_amd64.whl", hash = "sha256:3c9a24557edf25b60fded6ed99a9b5e4b287be1cc3857e76e18dd930e54240e3"}, ] pywin32 = [ - {file = "pywin32-227-cp27-cp27m-win32.whl", hash = "sha256:371fcc39416d736401f0274dd64c2302728c9e034808e37381b5e1b22be4a6b0"}, - {file = "pywin32-227-cp27-cp27m-win_amd64.whl", hash = "sha256:4cdad3e84191194ea6d0dd1b1b9bdda574ff563177d2adf2b4efec2a244fa116"}, - {file = "pywin32-227-cp35-cp35m-win32.whl", hash = "sha256:f4c5be1a293bae0076d93c88f37ee8da68136744588bc5e2be2f299a34ceb7aa"}, - {file = "pywin32-227-cp35-cp35m-win_amd64.whl", hash = "sha256:a929a4af626e530383a579431b70e512e736e9588106715215bf685a3ea508d4"}, - {file = "pywin32-227-cp36-cp36m-win32.whl", hash = "sha256:300a2db938e98c3e7e2093e4491439e62287d0d493fe07cce110db070b54c0be"}, - {file = "pywin32-227-cp36-cp36m-win_amd64.whl", hash = "sha256:9b31e009564fb95db160f154e2aa195ed66bcc4c058ed72850d047141b36f3a2"}, - {file = "pywin32-227-cp37-cp37m-win32.whl", hash = "sha256:47a3c7551376a865dd8d095a98deba954a98f326c6fe3c72d8726ca6e6b15507"}, - {file = "pywin32-227-cp37-cp37m-win_amd64.whl", hash = "sha256:31f88a89139cb2adc40f8f0e65ee56a8c585f629974f9e07622ba80199057511"}, - {file = "pywin32-227-cp38-cp38-win32.whl", hash = "sha256:7f18199fbf29ca99dff10e1f09451582ae9e372a892ff03a28528a24d55875bc"}, - {file = "pywin32-227-cp38-cp38-win_amd64.whl", hash = "sha256:7c1ae32c489dc012930787f06244426f8356e129184a02c25aef163917ce158e"}, - {file = "pywin32-227-cp39-cp39-win32.whl", hash = "sha256:c054c52ba46e7eb6b7d7dfae4dbd987a1bb48ee86debe3f245a2884ece46e295"}, - {file = "pywin32-227-cp39-cp39-win_amd64.whl", hash = "sha256:f27cec5e7f588c3d1051651830ecc00294f90728d19c3bf6916e6dba93ea357c"}, + {file = "pywin32-228-cp27-cp27m-win32.whl", hash = "sha256:37dc9935f6a383cc744315ae0c2882ba1768d9b06700a70f35dc1ce73cd4ba9c"}, + {file = "pywin32-228-cp27-cp27m-win_amd64.whl", hash = "sha256:11cb6610efc2f078c9e6d8f5d0f957620c333f4b23466931a247fb945ed35e89"}, + {file = "pywin32-228-cp35-cp35m-win32.whl", hash = "sha256:1f45db18af5d36195447b2cffacd182fe2d296849ba0aecdab24d3852fbf3f80"}, + {file = "pywin32-228-cp35-cp35m-win_amd64.whl", hash = "sha256:6e38c44097a834a4707c1b63efa9c2435f5a42afabff634a17f563bc478dfcc8"}, + {file = "pywin32-228-cp36-cp36m-win32.whl", hash = "sha256:ec16d44b49b5f34e99eb97cf270806fdc560dff6f84d281eb2fcb89a014a56a9"}, + {file = "pywin32-228-cp36-cp36m-win_amd64.whl", hash = "sha256:a60d795c6590a5b6baeacd16c583d91cce8038f959bd80c53bd9a68f40130f2d"}, + {file = "pywin32-228-cp37-cp37m-win32.whl", hash = "sha256:af40887b6fc200eafe4d7742c48417529a8702dcc1a60bf89eee152d1d11209f"}, + {file = "pywin32-228-cp37-cp37m-win_amd64.whl", hash = "sha256:00eaf43dbd05ba6a9b0080c77e161e0b7a601f9a3f660727a952e40140537de7"}, + {file = "pywin32-228-cp38-cp38-win32.whl", hash = "sha256:fa6ba028909cfc64ce9e24bcf22f588b14871980d9787f1e2002c99af8f1850c"}, + {file = "pywin32-228-cp38-cp38-win_amd64.whl", hash = "sha256:9b3466083f8271e1a5eb0329f4e0d61925d46b40b195a33413e0905dccb285e8"}, + {file = "pywin32-228-cp39-cp39-win32.whl", hash = "sha256:ed74b72d8059a6606f64842e7917aeee99159ebd6b8d6261c518d002837be298"}, + {file = "pywin32-228-cp39-cp39-win_amd64.whl", hash = "sha256:8319bafdcd90b7202c50d6014efdfe4fde9311b3ff15fd6f893a45c0868de203"}, ] pyxdg = [ - {file = "pyxdg-0.26-py2.py3-none-any.whl", hash = "sha256:1948ff8e2db02156c0cccd2529b43c0cff56ebaa71f5f021bbd755bc1419190e"}, - {file = "pyxdg-0.26.tar.gz", hash = "sha256:fe2928d3f532ed32b39c32a482b54136fe766d19936afc96c8f00645f9da1a06"}, + {file = "pyxdg-0.27-py2.py3-none-any.whl", hash = "sha256:2d6701ab7c74bbab8caa6a95e0a0a129b1643cf6c298bf7c569adec06d0709a0"}, + {file = "pyxdg-0.27.tar.gz", hash = "sha256:80bd93aae5ed82435f20462ea0208fb198d8eec262e831ee06ce9ddb6b91c5a5"}, ] requests = [ {file = "requests-2.24.0-py2.py3-none-any.whl", hash = "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898"}, diff --git a/pyproject.toml b/pyproject.toml index 21e7cf1..931de29 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,21 +7,21 @@ license = "MIT" [tool.poetry.dependencies] python = ">=3.7,<3.10" -click = "^7.0" -appdirs = "^1.4.3" -requests = "^2.22.0" -macholib = "^1.14" -termcolor = "^1.1.0" +click = "*" +appdirs = "*" +requests = "*" +macholib = "*" +termcolor = "*" PySide2 = "^5.15.1" -pywin32 = {version = "^227", platform = "windows"} -wmi = {version = "^1.4.9", platform = "windows"} -pyxdg = {version = "^0.26", platform = "linux"} -pyobjc-core = {version = "^6.1", platform = "darwin"} -pyobjc-framework-launchservices = {version = "^6.1", platform = "darwin"} +pywin32 = {version = "*", platform = "win32"} +wmi = {version = "*", platform = "win32"} +pyxdg = {version = "*", platform = "linux"} +pyobjc-core = {version = "*", platform = "darwin"} +pyobjc-framework-launchservices = {version = "*", platform = "darwin"} [tool.poetry.dev-dependencies] -pyinstaller = {version = "^3.6", platform = "darwin"} -setuptools = {version = "^45.2.0", platform = "windows"} +pyinstaller = {version = "*", platform = "darwin"} +setuptools = {version = "*", platform = "win32"} [tool.poetry.scripts] dangerzone = 'dangerzone:main' From 10dfc1441bcd066a7cc9803b4c368a12327f8590 Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Wed, 28 Oct 2020 12:13:09 -0700 Subject: [PATCH 7/9] Build the Wix wxs file on the fly --- .gitignore | 3 +- BUILD.md | 10 +- RELEASE.md | 1 - install/windows/Dangerzone.wxs | 228 ---------------------------- install/windows/build-wxs.py | 225 +++++++++++++++++++++++++++ install/windows/step1-build-exe.bat | 3 + 6 files changed, 235 insertions(+), 235 deletions(-) delete mode 100644 install/windows/Dangerzone.wxs create mode 100644 install/windows/build-wxs.py diff --git a/.gitignore b/.gitignore index 0302e4b..dea4911 100644 --- a/.gitignore +++ b/.gitignore @@ -131,4 +131,5 @@ dmypy.json .vscode *.tar.gz deb_dist -.DS_Store \ No newline at end of file +.DS_Store +install/windows/Dangerzone.wxs \ No newline at end of file diff --git a/BUILD.md b/BUILD.md index b938443..ad4a05e 100644 --- a/BUILD.md +++ b/BUILD.md @@ -113,8 +113,8 @@ Download and install the [Windows 10 SDK](https://developer.microsoft.com/en-US/ Add the following directories to the path: -* `C:\Program Files (x86)\Windows Kits\10\bin\10.0.18362.0\x86` -* `C:\Program Files (x86)\Windows Kits\10\Redist\10.0.18362.0\ucrt\DLLs\x86` +* `C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x86` +* `C:\Program Files (x86)\Windows Kits\10\Redist\ucrt\DLLs\x86` ### If you want the .exe to not get falsely flagged as malicious by anti-virus software @@ -122,7 +122,7 @@ Dangerzone uses PyInstaller to turn the python source code into Windows executab Here's how to compile the PyInstaller bootloader: -Download and install [Microsoft Build Tools for Visual Studio 2017](https://www.visualstudio.com/downloads/#build-tools-for-visual-studio-2019). I downloaded `vs_buildtools__1378184674.1581551596.exe`. In the installer, check the box next to "C++ build tools". Click "Individual components", and under "Compilers, build tools and runtimes", check "Windows Universal CRT SDK". Then click install. When installation is done, you may have to reboot your computer. +Download and install [Microsoft Build Tools for Visual Studio 2019](https://www.visualstudio.com/downloads/#build-tools-for-visual-studio-2019). I downloaded `vs_buildtools__719988613.1603831511.exe`. In the installer, check the box next to "C++ build tools". Click "Individual components", and under "Compilers, build tools and runtimes", check "Windows Universal CRT SDK". Then click install. When installation is done, you may have to reboot your computer. Then, enable the 32-bit Visual C++ Toolset on the Command Line like this: @@ -136,7 +136,7 @@ Change to a folder where you keep source code, and clone the PyInstaller git rep ``` git clone https://github.com/pyinstaller/pyinstaller.git cd pyinstaller -git tag -v v3.6 +git tag -v v4.0 ``` (Note that ideally you would verify the git tag, but the PGP key that has signed the v3.5 git tag for is not published anywhere, so this isn't possible. See [this issue](https://github.com/pyinstaller/pyinstaller/issues/4430).) @@ -170,7 +170,7 @@ Now the next time you use PyInstaller to build dangerzone, the `.exe` file shoul * Go to https://dotnet.microsoft.com/download/dotnet-framework and download and install .NET Framework 3.5 SP1 Runtime. I downloaded `dotnetfx35.exe`. * Go to https://wixtoolset.org/releases/ and download and install WiX toolset. I downloaded `wix311.exe`. -* Add `C:\Program Files (x86)\WiX Toolset v3.1.1\bin` to the path. +* Add `C:\Program Files (x86)\WiX Toolset v3.11\bin` to the path. ### If you want to sign binaries with Authenticode diff --git a/RELEASE.md b/RELEASE.md index dad4956..b7ba10e 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -8,7 +8,6 @@ Before making a release, all of these should be complete: * Update `version` in `pyproject.toml` * Update `dangerzone_version` in `dangerzone/__init__.py` -* Update `ProductVersion` in `install/windows/Dangerzone.wxs` * Update version and download links in `README.md` * CHANGELOG.md should be updated to include a list of all major changes since the last release * There must be a PGP-signed git tag for the version, e.g. for dangerzone 0.1.0, the tag must be `v0.1.0` diff --git a/install/windows/Dangerzone.wxs b/install/windows/Dangerzone.wxs deleted file mode 100644 index 527a9c6..0000000 --- a/install/windows/Dangerzone.wxs +++ /dev/null @@ -1,228 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - NOT NEWERVERSIONDETECTED - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/install/windows/build-wxs.py b/install/windows/build-wxs.py new file mode 100644 index 0000000..24d74a9 --- /dev/null +++ b/install/windows/build-wxs.py @@ -0,0 +1,225 @@ +#!/usr/bin/env python3 +import os +import uuid +import xml.etree.ElementTree as ET + + +def build_data(dirname, dir_prefix, id_, name): + data = { + "id": id_, + "name": name, + "files": [], + "dirs": [], + } + + for basename in os.listdir(dirname): + filename = os.path.join(dirname, basename) + if os.path.isfile(filename): + data["files"].append(os.path.join(dir_prefix, basename)) + elif os.path.isdir(filename): + if id_ == "INSTALLDIR": + id_prefix = "Folder" + else: + id_prefix = id_ + + data["dirs"].append( + build_data( + os.path.join(dirname, basename), + os.path.join(dir_prefix, basename), + f"{id_prefix}{basename.capitalize()}", + basename, + ) + ) + + if len(data["files"]) > 0: + if id_ == "INSTALLDIR": + data["component_id"] = "ApplicationFiles" + else: + data["component_id"] = "FolderComponent" + id_[len("Folder") :] + data["component_guid"] = str(uuid.uuid4()) + + return data + + +def build_dir_xml(root, data): + attrs = {} + if "id" in data: + attrs["Id"] = data["id"] + if "name" in data: + attrs["Name"] = data["name"] + el = ET.SubElement(root, "Directory", attrs) + for subdata in data["dirs"]: + build_dir_xml(el, subdata) + + +def build_components_xml(root, data): + component_ids = [] + if "component_id" in data: + component_ids.append(data["component_id"]) + + for subdata in data["dirs"]: + if "component_guid" in subdata: + dir_ref_el = ET.SubElement(root, "DirectoryRef", Id=subdata["id"]) + component_el = ET.SubElement( + dir_ref_el, + "Component", + Id=subdata["component_id"], + Guid=subdata["component_guid"], + ) + for filename in subdata["files"]: + file_el = ET.SubElement( + component_el, "File", Source=filename, Id="file_" + uuid.uuid4().hex + ) + + component_ids += build_components_xml(root, subdata) + + return component_ids + + +def main(): + version_filename = os.path.join( + os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), + "dangerzone", + "__init__.py", + ) + with open(version_filename) as f: + for line in f.readlines(): + if line.startswith("dangerzone_version ="): + version = line.split('"')[1] + break + + dist_dir = os.path.join( + os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), + "dist", + "dangerzone", + ) + if not os.path.exists(dist_dir): + print( + "You must run step1-build-exe.bat to build dangerzone binary before running this" + ) + return + + data = { + "id": "TARGETDIR", + "name": "SourceDir", + "dirs": [ + { + "id": "ProgramFilesFolder", + "dirs": [], + } + ], + } + + data["dirs"][0]["dirs"].append( + build_data( + dist_dir, + os.path.join("..", "..", "dist", "dangerzone"), + "INSTALLDIR", + "Dangerzone", + ) + ) + + root_el = ET.Element("Wix", xmlns="http://schemas.microsoft.com/wix/2006/wi") + product_el = ET.SubElement( + root_el, + "Product", + Name="Dangerzone", + Manufacturer="First Look Media", + Id="f40ff0a9-ebf8-4e1e-9bce-6ab5c74fe119", + UpgradeCode="$(var.ProductUpgradeCode)", + Language="1033", + Codepage="1252", + Version="$(var.ProductVersion)", + ) + ET.SubElement( + product_el, + "Package", + Id="*", + Keywords="Installer", + Description="Dangerzone $(var.ProductVersion) Installer", + Manufacturer="First Look Media", + InstallerVersion="100", + Languages="1033", + Compressed="yes", + SummaryCodepage="1252", + ) + ET.SubElement(product_el, "Media", Id="1", Cabinet="product.cab", EmbedCab="yes") + ET.SubElement( + product_el, "Icon", Id="ProductIcon", SourceFile="..\\..\\share\\dangerzone.ico" + ) + ET.SubElement(product_el, "Property", Id="ARPPRODUCTICON", Value="ProductIcon") + ET.SubElement( + product_el, + "Property", + Id="ARPHELPLINK", + Value="https://github.com/firstlookmedia/dangerzone", + ) + ET.SubElement( + product_el, + "Property", + Id="ARPURLINFOABOUT", + Value="https://tech.firstlook.media", + ) + ET.SubElement(product_el, "UIRef", Id="WixUI_Minimal") + ET.SubElement(product_el, "UIRef", Id="WixUI_ErrorProgressText") + ET.SubElement( + product_el, + "WixVariable", + Id="WixUILicenseRtf", + Value="..\\..\\install\\windows\\license.rtf", + ) + ET.SubElement( + product_el, + "WixVariable", + Id="WixUIDialogBmp", + Value="..\\..\\install\\windows\\dialog.bmp", + ) + upgrade_el = ET.SubElement(product_el, "Upgrade", Id="$(var.ProductUpgradeCode)") + ET.SubElement( + upgrade_el, + "UpgradeVersion", + Minimum="$(var.ProductVersion)", + OnlyDetect="yes", + Property="NEWERVERSIONDETECTED", + ) + ET.SubElement( + upgrade_el, + "UpgradeVersion", + Minimum="0.0.0", + Maximum="$(var.ProductVersion)", + IncludeMinimum="yes", + IncludeMaximum="no", + Property="OLDERVERSIONBEINGUPGRADED", + ) + condition_el = ET.SubElement( + product_el, + "Condition", + Message="A newer version of this software is already installed.", + ) + condition_el.text = "NOT NEWERVERSIONDETECTED" + + build_dir_xml(product_el, data) + component_ids = build_components_xml(product_el, data) + + install_exec_seq_el = ET.SubElement( + product_el, + "InstallExecuteSequence", + ) + ET.SubElement( + install_exec_seq_el, "RemoveExistingProducts", After="InstallValidate" + ) + + feature_el = ET.SubElement(product_el, "Feature", Id="DefaultFeature", Level="1") + for component_id in component_ids: + ET.SubElement(feature_el, "ComponentRef", Id=component_id) + + print('') + print(f'') + print('') + + ET.indent(root_el) + ET.dump(root_el) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/install/windows/step1-build-exe.bat b/install/windows/step1-build-exe.bat index dacc95a..b92ac8b 100644 --- a/install/windows/step1-build-exe.bat +++ b/install/windows/step1-build-exe.bat @@ -7,3 +7,6 @@ pyinstaller install\pyinstaller\pyinstaller.spec REM code sign dangerzone.exe signtool.exe sign /v /d "Dangerzone" /a /tr http://time.certum.pl/ dist\dangerzone\dangerzone.exe + +REM build the wix file +python install\windows\build-wxs.py > install\windows\Dangerzone.wxs From 1116c9a0299e3203d803d3e8c78211e105b9341e Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Wed, 28 Oct 2020 16:48:16 -0700 Subject: [PATCH 8/9] Make Windows docker link clickable, and make Windows installer add a start menu shortcut --- dangerzone/docker_installer.py | 1 + install/windows/build-wxs.py | 486 ++++++++++++++++++--------------- 2 files changed, 263 insertions(+), 224 deletions(-) diff --git a/dangerzone/docker_installer.py b/dangerzone/docker_installer.py index 3619ef1..6def8ee 100644 --- a/dangerzone/docker_installer.py +++ b/dangerzone/docker_installer.py @@ -74,6 +74,7 @@ class DockerInstaller(QtWidgets.QDialog): self.task_label = QtWidgets.QLabel() self.task_label.setAlignment(QtCore.Qt.AlignCenter) self.task_label.setWordWrap(True) + self.task_label.setOpenExternalLinks(True) self.progress = QtWidgets.QProgressBar() self.progress.setMinimum(0) diff --git a/install/windows/build-wxs.py b/install/windows/build-wxs.py index 24d74a9..193de67 100644 --- a/install/windows/build-wxs.py +++ b/install/windows/build-wxs.py @@ -1,225 +1,263 @@ -#!/usr/bin/env python3 -import os -import uuid -import xml.etree.ElementTree as ET - - -def build_data(dirname, dir_prefix, id_, name): - data = { - "id": id_, - "name": name, - "files": [], - "dirs": [], - } - - for basename in os.listdir(dirname): - filename = os.path.join(dirname, basename) - if os.path.isfile(filename): - data["files"].append(os.path.join(dir_prefix, basename)) - elif os.path.isdir(filename): - if id_ == "INSTALLDIR": - id_prefix = "Folder" - else: - id_prefix = id_ - - data["dirs"].append( - build_data( - os.path.join(dirname, basename), - os.path.join(dir_prefix, basename), - f"{id_prefix}{basename.capitalize()}", - basename, - ) - ) - - if len(data["files"]) > 0: - if id_ == "INSTALLDIR": - data["component_id"] = "ApplicationFiles" - else: - data["component_id"] = "FolderComponent" + id_[len("Folder") :] - data["component_guid"] = str(uuid.uuid4()) - - return data - - -def build_dir_xml(root, data): - attrs = {} - if "id" in data: - attrs["Id"] = data["id"] - if "name" in data: - attrs["Name"] = data["name"] - el = ET.SubElement(root, "Directory", attrs) - for subdata in data["dirs"]: - build_dir_xml(el, subdata) - - -def build_components_xml(root, data): - component_ids = [] - if "component_id" in data: - component_ids.append(data["component_id"]) - - for subdata in data["dirs"]: - if "component_guid" in subdata: - dir_ref_el = ET.SubElement(root, "DirectoryRef", Id=subdata["id"]) - component_el = ET.SubElement( - dir_ref_el, - "Component", - Id=subdata["component_id"], - Guid=subdata["component_guid"], - ) - for filename in subdata["files"]: - file_el = ET.SubElement( - component_el, "File", Source=filename, Id="file_" + uuid.uuid4().hex - ) - - component_ids += build_components_xml(root, subdata) - - return component_ids - - -def main(): - version_filename = os.path.join( - os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), - "dangerzone", - "__init__.py", - ) - with open(version_filename) as f: - for line in f.readlines(): - if line.startswith("dangerzone_version ="): - version = line.split('"')[1] - break - - dist_dir = os.path.join( - os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), - "dist", - "dangerzone", - ) - if not os.path.exists(dist_dir): - print( - "You must run step1-build-exe.bat to build dangerzone binary before running this" - ) - return - - data = { - "id": "TARGETDIR", - "name": "SourceDir", - "dirs": [ - { - "id": "ProgramFilesFolder", - "dirs": [], - } - ], - } - - data["dirs"][0]["dirs"].append( - build_data( - dist_dir, - os.path.join("..", "..", "dist", "dangerzone"), - "INSTALLDIR", - "Dangerzone", - ) - ) - - root_el = ET.Element("Wix", xmlns="http://schemas.microsoft.com/wix/2006/wi") - product_el = ET.SubElement( - root_el, - "Product", - Name="Dangerzone", - Manufacturer="First Look Media", - Id="f40ff0a9-ebf8-4e1e-9bce-6ab5c74fe119", - UpgradeCode="$(var.ProductUpgradeCode)", - Language="1033", - Codepage="1252", - Version="$(var.ProductVersion)", - ) - ET.SubElement( - product_el, - "Package", - Id="*", - Keywords="Installer", - Description="Dangerzone $(var.ProductVersion) Installer", - Manufacturer="First Look Media", - InstallerVersion="100", - Languages="1033", - Compressed="yes", - SummaryCodepage="1252", - ) - ET.SubElement(product_el, "Media", Id="1", Cabinet="product.cab", EmbedCab="yes") - ET.SubElement( - product_el, "Icon", Id="ProductIcon", SourceFile="..\\..\\share\\dangerzone.ico" - ) - ET.SubElement(product_el, "Property", Id="ARPPRODUCTICON", Value="ProductIcon") - ET.SubElement( - product_el, - "Property", - Id="ARPHELPLINK", - Value="https://github.com/firstlookmedia/dangerzone", - ) - ET.SubElement( - product_el, - "Property", - Id="ARPURLINFOABOUT", - Value="https://tech.firstlook.media", - ) - ET.SubElement(product_el, "UIRef", Id="WixUI_Minimal") - ET.SubElement(product_el, "UIRef", Id="WixUI_ErrorProgressText") - ET.SubElement( - product_el, - "WixVariable", - Id="WixUILicenseRtf", - Value="..\\..\\install\\windows\\license.rtf", - ) - ET.SubElement( - product_el, - "WixVariable", - Id="WixUIDialogBmp", - Value="..\\..\\install\\windows\\dialog.bmp", - ) - upgrade_el = ET.SubElement(product_el, "Upgrade", Id="$(var.ProductUpgradeCode)") - ET.SubElement( - upgrade_el, - "UpgradeVersion", - Minimum="$(var.ProductVersion)", - OnlyDetect="yes", - Property="NEWERVERSIONDETECTED", - ) - ET.SubElement( - upgrade_el, - "UpgradeVersion", - Minimum="0.0.0", - Maximum="$(var.ProductVersion)", - IncludeMinimum="yes", - IncludeMaximum="no", - Property="OLDERVERSIONBEINGUPGRADED", - ) - condition_el = ET.SubElement( - product_el, - "Condition", - Message="A newer version of this software is already installed.", - ) - condition_el.text = "NOT NEWERVERSIONDETECTED" - - build_dir_xml(product_el, data) - component_ids = build_components_xml(product_el, data) - - install_exec_seq_el = ET.SubElement( - product_el, - "InstallExecuteSequence", - ) - ET.SubElement( - install_exec_seq_el, "RemoveExistingProducts", After="InstallValidate" - ) - - feature_el = ET.SubElement(product_el, "Feature", Id="DefaultFeature", Level="1") - for component_id in component_ids: - ET.SubElement(feature_el, "ComponentRef", Id=component_id) - - print('') - print(f'') - print('') - - ET.indent(root_el) - ET.dump(root_el) - - -if __name__ == "__main__": +#!/usr/bin/env python3 +import os +import uuid +import xml.etree.ElementTree as ET + + +def build_data(dirname, dir_prefix, id_, name): + data = { + "id": id_, + "name": name, + "files": [], + "dirs": [], + } + + for basename in os.listdir(dirname): + filename = os.path.join(dirname, basename) + if os.path.isfile(filename): + data["files"].append(os.path.join(dir_prefix, basename)) + elif os.path.isdir(filename): + if id_ == "INSTALLDIR": + id_prefix = "Folder" + else: + id_prefix = id_ + + data["dirs"].append( + build_data( + os.path.join(dirname, basename), + os.path.join(dir_prefix, basename), + f"{id_prefix}{basename.capitalize()}", + basename, + ) + ) + + if len(data["files"]) > 0: + if id_ == "INSTALLDIR": + data["component_id"] = "ApplicationFiles" + else: + data["component_id"] = "FolderComponent" + id_[len("Folder") :] + data["component_guid"] = str(uuid.uuid4()) + + return data + + +def build_dir_xml(root, data): + attrs = {} + if "id" in data: + attrs["Id"] = data["id"] + if "name" in data: + attrs["Name"] = data["name"] + el = ET.SubElement(root, "Directory", attrs) + for subdata in data["dirs"]: + build_dir_xml(el, subdata) + + # If this is the ProgramMenuSubfolder, add the menu component + if "id" in data and data["id"] == "ProgramMenuSubfolder": + component_el = ET.SubElement( + el, + "Component", + Id="ApplicationShortcuts", + Guid="539e7de8-a124-4c09-aa55-0dd516aad7bc", + ) + ET.SubElement( + component_el, + "Shortcut", + Id="ApplicationShortcut1", + Name="Dangerzone", + Description="Dangerzone", + Target="[INSTALLDIR]dangerzone.exe", + WorkingDirectory="INSTALLDIR", + ) + ET.SubElement( + component_el, + "RegistryValue", + Root="HKCU", + Key="Software\First Look Media\Dangerzone", + Name="installed", + Type="integer", + Value="1", + KeyPath="yes", + ) + ET.SubElement( + component_el, "RemoveFolder", Id="ProgramMenuSubfolder", On="uninstall" + ) + + +def build_components_xml(root, data): + component_ids = [] + if "component_id" in data: + component_ids.append(data["component_id"]) + + for subdata in data["dirs"]: + if "component_guid" in subdata: + dir_ref_el = ET.SubElement(root, "DirectoryRef", Id=subdata["id"]) + component_el = ET.SubElement( + dir_ref_el, + "Component", + Id=subdata["component_id"], + Guid=subdata["component_guid"], + ) + for filename in subdata["files"]: + file_el = ET.SubElement( + component_el, "File", Source=filename, Id="file_" + uuid.uuid4().hex + ) + + component_ids += build_components_xml(root, subdata) + + return component_ids + + +def main(): + version_filename = os.path.join( + os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), + "dangerzone", + "__init__.py", + ) + with open(version_filename) as f: + for line in f.readlines(): + if line.startswith("dangerzone_version ="): + version = line.split('"')[1] + break + + dist_dir = os.path.join( + os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), + "dist", + "dangerzone", + ) + if not os.path.exists(dist_dir): + print( + "You must run step1-build-exe.bat to build dangerzone binary before running this" + ) + return + + data = { + "id": "TARGETDIR", + "name": "SourceDir", + "dirs": [ + { + "id": "ProgramFilesFolder", + "dirs": [], + }, + { + "id": "ProgramMenuFolder", + "dirs": [ + {"id": "ProgramMenuSubfolder", "name": "Dangerzone", "dirs": []} + ], + }, + ], + } + + data["dirs"][0]["dirs"].append( + build_data( + dist_dir, + os.path.join("..", "..", "dist", "dangerzone"), + "INSTALLDIR", + "Dangerzone", + ) + ) + + root_el = ET.Element("Wix", xmlns="http://schemas.microsoft.com/wix/2006/wi") + product_el = ET.SubElement( + root_el, + "Product", + Name="Dangerzone", + Manufacturer="First Look Media", + Id="f40ff0a9-ebf8-4e1e-9bce-6ab5c74fe119", + UpgradeCode="$(var.ProductUpgradeCode)", + Language="1033", + Codepage="1252", + Version="$(var.ProductVersion)", + ) + ET.SubElement( + product_el, + "Package", + Id="*", + Keywords="Installer", + Description="Dangerzone $(var.ProductVersion) Installer", + Manufacturer="First Look Media", + InstallerVersion="100", + Languages="1033", + Compressed="yes", + SummaryCodepage="1252", + ) + ET.SubElement(product_el, "Media", Id="1", Cabinet="product.cab", EmbedCab="yes") + ET.SubElement( + product_el, "Icon", Id="ProductIcon", SourceFile="..\\..\\share\\dangerzone.ico" + ) + ET.SubElement(product_el, "Property", Id="ARPPRODUCTICON", Value="ProductIcon") + ET.SubElement( + product_el, + "Property", + Id="ARPHELPLINK", + Value="https://github.com/firstlookmedia/dangerzone", + ) + ET.SubElement( + product_el, + "Property", + Id="ARPURLINFOABOUT", + Value="https://tech.firstlook.media", + ) + ET.SubElement(product_el, "UIRef", Id="WixUI_Minimal") + ET.SubElement(product_el, "UIRef", Id="WixUI_ErrorProgressText") + ET.SubElement( + product_el, + "WixVariable", + Id="WixUILicenseRtf", + Value="..\\..\\install\\windows\\license.rtf", + ) + ET.SubElement( + product_el, + "WixVariable", + Id="WixUIDialogBmp", + Value="..\\..\\install\\windows\\dialog.bmp", + ) + upgrade_el = ET.SubElement(product_el, "Upgrade", Id="$(var.ProductUpgradeCode)") + ET.SubElement( + upgrade_el, + "UpgradeVersion", + Minimum="$(var.ProductVersion)", + OnlyDetect="yes", + Property="NEWERVERSIONDETECTED", + ) + ET.SubElement( + upgrade_el, + "UpgradeVersion", + Minimum="0.0.0", + Maximum="$(var.ProductVersion)", + IncludeMinimum="yes", + IncludeMaximum="no", + Property="OLDERVERSIONBEINGUPGRADED", + ) + condition_el = ET.SubElement( + product_el, + "Condition", + Message="A newer version of this software is already installed.", + ) + condition_el.text = "NOT NEWERVERSIONDETECTED" + + build_dir_xml(product_el, data) + component_ids = build_components_xml(product_el, data) + + install_exec_seq_el = ET.SubElement( + product_el, + "InstallExecuteSequence", + ) + ET.SubElement( + install_exec_seq_el, "RemoveExistingProducts", After="InstallValidate" + ) + + feature_el = ET.SubElement(product_el, "Feature", Id="DefaultFeature", Level="1") + for component_id in component_ids: + ET.SubElement(feature_el, "ComponentRef", Id=component_id) + ET.SubElement(feature_el, "ComponentRef", Id="ApplicationShortcuts") + + print('') + print(f'') + print('') + + ET.indent(root_el) + ET.dump(root_el) + + +if __name__ == "__main__": main() \ No newline at end of file From 60e827062079f34b5a83c87c0f7dfa48759d5a20 Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Wed, 28 Oct 2020 16:50:17 -0700 Subject: [PATCH 9/9] No need to install Qt for macOS in build instructions --- BUILD.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/BUILD.md b/BUILD.md index ad4a05e..6346ff3 100644 --- a/BUILD.md +++ b/BUILD.md @@ -48,8 +48,6 @@ Create a .rpm: Download and install Python 3.9.0 from https://www.python.org/downloads/release/python-390/. I downloaded `python-3.9.0-macosx10.9.pkg`. -Install Qt 5.14.0 for macOS from https://www.qt.io/offline-installers. I downloaded `qt-opensource-mac-x64-5.14.0.dmg`. In the installer, you can skip making an account, and all you need is `Qt` > `Qt 5.14.0` > `macOS`. - If you don't have it already, install poetry (`pip3 install --user poetry`). Then install dependencies: ```sh