From 17a585f6142ba5f6f64b90ab5e5fe136c153856b Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Tue, 11 Feb 2020 16:48:52 -0800 Subject: [PATCH 01/10] Make DockerInstaller also install the Windows version of Docker --- BUILD.md | 22 ++++- dangerzone/__init__.py | 31 ++++++- dangerzone/common.py | 14 ++- dangerzone/docker_installer.py | 151 ++++++++++++++++++++++----------- 4 files changed, 161 insertions(+), 57 deletions(-) diff --git a/BUILD.md b/BUILD.md index 7752241..c5c91d7 100644 --- a/BUILD.md +++ b/BUILD.md @@ -31,8 +31,6 @@ Create a .deb: ## macOS -## 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`. @@ -70,4 +68,22 @@ And then run `build_app.py --with-codesign`: pipenv run ./install/macos/build_app.py --with-codesign ``` -The output is in the `dist` folder. \ No newline at end of file +The output is in the `dist` folder. + +## Windows + +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. + +Open a command prompt and cd to the gpgsync folder. If you don't have it already, install pipenv (`pip install pipenv`). Then install dependencies: + +``` +python -m pipenv install --dev +``` + +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`. + +After that you can launch GPG Sync during development with: + +``` +python -m pipenv run python dev_scripts\dangerzone +``` diff --git a/dangerzone/__init__.py b/dangerzone/__init__.py index 72e6eff..83b4e95 100644 --- a/dangerzone/__init__.py +++ b/dangerzone/__init__.py @@ -8,7 +8,12 @@ import time from .common import Common from .main_window import MainWindow -from .docker_installer import is_docker_installed, is_docker_ready, DockerInstaller +from .docker_installer import ( + is_docker_installed, + is_docker_ready, + launch_docker_windows, + DockerInstaller, +) dangerzone_version = "0.1.0" @@ -49,6 +54,30 @@ def main(filename): return + if platform.system() == "Windows": + if not is_docker_installed(common): + print("Docker is not installed") + docker_installer = DockerInstaller(common) + docker_installer.start() + # Quit after the installer runs, because it requires rebooting + return + + if not is_docker_ready(common): + print("Docker is not running") + launch_docker_windows() + + # Wait up to 20 minutes for docker to be ready + for i in range(120): + if is_docker_ready(common): + main(filename) + return + + print("Waiting for docker to be available ...") + time.sleep(1) + + # Give up + print("Docker not available, giving up") + # Main window main_window = MainWindow(common) diff --git a/dangerzone/common.py b/dangerzone/common.py index 8a79777..95dc508 100644 --- a/dangerzone/common.py +++ b/dangerzone/common.py @@ -30,8 +30,14 @@ class Common(object): # 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 - self.pixel_dir = tempfile.TemporaryDirectory(prefix="/tmp/dangerzone-pixel-") - self.safe_dir = tempfile.TemporaryDirectory(prefix="/tmp/dangerzone-safe-") + if platform.system() == "Windows": + self.pixel_dir = tempfile.TemporaryDirectory(prefix="dangerzone-pixel-") + self.safe_dir = tempfile.TemporaryDirectory(prefix="dangerzone-safe-") + else: + self.pixel_dir = tempfile.TemporaryDirectory( + prefix="/tmp/dangerzone-pixel-" + ) + self.safe_dir = tempfile.TemporaryDirectory(prefix="/tmp/dangerzone-safe-") print( f"Temporary directories created, dangerous={self.pixel_dir.name}, safe={self.safe_dir.name}" ) @@ -51,6 +57,10 @@ class Common(object): # Container runtime if platform.system() == "Darwin": self.container_runtime = "/usr/local/bin/docker" + elif platform.system() == "Windows": + self.container_runtime = ( + "C:\\Program Files\\Docker\\Docker\\resources\\bin\\docker.exe" + ) else: self.container_runtime = "podman" diff --git a/dangerzone/docker_installer.py b/dangerzone/docker_installer.py index eb1a1ea..82db353 100644 --- a/dangerzone/docker_installer.py +++ b/dangerzone/docker_installer.py @@ -5,17 +5,23 @@ import tempfile import subprocess import shutil import time +import platform from PyQt5 import QtCore, QtGui, QtWidgets def is_docker_installed(common): - # Does the docker binary exist? - if os.path.isdir("/Applications/Docker.app") and os.path.exists( - common.container_runtime - ): - # Is it executable? - st = os.stat(common.container_runtime) - return bool(st.st_mode & stat.S_IXOTH) + if platform.system() == "Darwin": + # Does the docker binary exist? + if os.path.isdir("/Applications/Docker.app") and os.path.exists( + common.container_runtime + ): + # Is it executable? + st = os.stat(common.container_runtime) + return bool(st.st_mode & stat.S_IXOTH) + + if platform.system() == "Windows": + return os.path.exists(common.container_runtime) + return False @@ -28,6 +34,11 @@ def is_docker_ready(common): return False +def launch_docker_windows(): + docker_desktop_path = "C:\\Program Files\\Docker\\Docker\\Docker Desktop.exe" + subprocess.Popen([docker_desktop_path]) + + class DockerInstaller(QtWidgets.QDialog): def __init__(self, common): super(DockerInstaller, self).__init__() @@ -36,7 +47,11 @@ class DockerInstaller(QtWidgets.QDialog): self.setWindowTitle("dangerzone") self.setWindowIcon(QtGui.QIcon(self.common.get_resource_path("logo.png"))) - label = QtWidgets.QLabel("Dangerzone for macOS requires Docker") + label = QtWidgets.QLabel() + if platform.system() == "Darwin": + label.setText("Dangerzone for macOS requires Docker") + elif platform.system() == "Windows": + label.setText("Dangerzone for Windows requires Docker") label.setStyleSheet("QLabel { font-weight: bold; }") label.setAlignment(QtCore.Qt.AlignCenter) @@ -50,17 +65,21 @@ class DockerInstaller(QtWidgets.QDialog): self.install_button.setStyleSheet("QPushButton { font-weight: bold; }") self.install_button.clicked.connect(self.install_clicked) self.install_button.hide() - self.launch_button = QtWidgets.QPushButton("Launch Docker") - self.launch_button.setStyleSheet("QPushButton { font-weight: bold; }") - self.launch_button.clicked.connect(self.launch_clicked) - self.launch_button.hide() + + if platform.system() == "Darwin": + self.launch_button = QtWidgets.QPushButton("Launch Docker") + self.launch_button.setStyleSheet("QPushButton { font-weight: bold; }") + self.launch_button.clicked.connect(self.launch_clicked) + self.launch_button.hide() + self.cancel_button = QtWidgets.QPushButton("Cancel") self.cancel_button.clicked.connect(self.cancel_clicked) buttons_layout = QtWidgets.QHBoxLayout() buttons_layout.addStretch() buttons_layout.addWidget(self.install_button) - buttons_layout.addWidget(self.launch_button) + if platform.system() == "Darwin": + buttons_layout.addWidget(self.launch_button) buttons_layout.addWidget(self.cancel_button) buttons_layout.addStretch() @@ -72,8 +91,14 @@ class DockerInstaller(QtWidgets.QDialog): layout.addStretch() self.setLayout(layout) - self.tmp_dir = tempfile.TemporaryDirectory(prefix="/tmp/dangerzone-docker-") - self.dmg_filename = os.path.join(self.tmp_dir.name, "Docker.dmg") + if platform.system == "Darwin": + self.tmp_dir = tempfile.TemporaryDirectory(prefix="/tmp/dangerzone-docker-") + self.installer_filename = os.path.join(self.tmp_dir.name, "Docker.dmg") + else: + self.tmp_dir = tempfile.TemporaryDirectory(prefix="dangerzone-docker-") + self.installer_filename = os.path.join( + self.tmp_dir.name, "Docker for Windows Installer.exe" + ) # Threads self.download_t = None @@ -105,19 +130,22 @@ class DockerInstaller(QtWidgets.QDialog): self.timer.start(10) def start_download(self): - self.download_t = Downloader(self.dmg_filename) + self.download_t = Downloader(self.installer_filename) self.download_t.download_finished.connect(self.download_finished) self.download_t.download_failed.connect(self.download_failed) self.download_t.update_progress.connect(self.update_progress) self.download_t.start() def install_finished(self): - self.task_label.setText("Finished installing Docker") + if platform.system() == "Darwin": + self.task_label.setText("Finished installing Docker") + self.launch_button.show() + self.cancel_button.setEnabled(True) + elif platform.system == "Windows": + self.task_label.setText("Reboot to finish installing Docker") self.install_t = None self.progress.hide() self.install_button.hide() - self.launch_button.show() - self.cancel_button.setEnabled(True) def install_failed(self, exception): print(f"Install failed: {exception}") @@ -141,16 +169,17 @@ class DockerInstaller(QtWidgets.QDialog): self.timer.start(10) def start_installer(self): - self.install_t = Installer(self.dmg_filename) + self.install_t = Installer(self.installer_filename) self.install_t.install_finished.connect(self.install_finished) self.install_t.install_failed.connect(self.install_failed) self.install_t.update_task_label.connect(self.update_task_label) self.install_t.start() def launch_clicked(self): - print("Launching Docker") - self.accept() - subprocess.Popen(["open", "-a", "Docker.app"]) + if system.platform() == "Darwin": + print("Launching Docker") + self.accept() + subprocess.Popen(["open", "-a", "Docker.app"]) def cancel_clicked(self): self.reject() @@ -175,22 +204,25 @@ class Downloader(QtCore.QThread): download_failed = QtCore.pyqtSignal(int) update_progress = QtCore.pyqtSignal(int, int) - def __init__(self, dmg_filename): + def __init__(self, installer_filename): super(Downloader, self).__init__() - self.dmg_filename = dmg_filename + self.installer_filename = installer_filename + + if platform.system() == "Darwin": + self.installer_url = "https://download.docker.com/mac/stable/Docker.dmg" + elif platform.system() == "Windows": + self.installer_url = "https://download.docker.com/win/stable/Docker%20for%20Windows%20Installer.exe" def run(self): - print(f"Downloading docker to {self.dmg_filename}") - with requests.get( - "https://download.docker.com/mac/stable/Docker.dmg", stream=True - ) as r: + print(f"Downloading docker to {self.installer_filename}") + with requests.get(self.installer_url, stream=True) as r: if r.status_code != 200: self.download_failed.emit(r.status_code) return total_bytes = int(r.headers.get("content-length")) downloaded_bytes = 0 - with open(self.dmg_filename, "wb") as f: + with open(self.installer_filename, "wb") as f: for chunk in r.iter_content(chunk_size=8192): if chunk: # filter out keep-alive new chunks downloaded_bytes += f.write(chunk) @@ -205,34 +237,51 @@ class Installer(QtCore.QThread): install_failed = QtCore.pyqtSignal(str) update_task_label = QtCore.pyqtSignal(str) - def __init__(self, dmg_filename): + def __init__(self, installer_filename): super(Installer, self).__init__() - self.dmg_filename = dmg_filename + self.installer_filename = installer_filename def run(self): print(f"Installing Docker") - try: - # Mount the dmg - self.update_task_label.emit(f"Mounting Docker.dmg") - subprocess.run(["hdiutil", "attach", "-nobrowse", self.dmg_filename]) - # Copy Docker.app to Applications - self.update_task_label.emit("Copying Docker into Applications") - shutil.copytree("/Volumes/Docker/Docker.app", "/Applications/Docker.app") + if platform.system() == "Darwin": + try: + # Mount the dmg + self.update_task_label.emit(f"Mounting Docker.dmg") + subprocess.run( + ["hdiutil", "attach", "-nobrowse", self.installer_filename] + ) - # Sync - self.update_task_label.emit("Syncing filesystem") - subprocess.run(["sync"]) + # Copy Docker.app to Applications + self.update_task_label.emit("Copying Docker into Applications") + shutil.copytree( + "/Volumes/Docker/Docker.app", "/Applications/Docker.app" + ) - # Wait, to prevent early crash - time.sleep(1) + # Sync + self.update_task_label.emit("Syncing filesystem") + subprocess.run(["sync"]) - # Unmount the dmg - self.update_task_label.emit(f"Unmounting /Volumes/Docker") - subprocess.run(["hdiutil", "detach", "/Volumes/Docker"]) + # Wait, to prevent early crash + time.sleep(1) - self.install_finished.emit() + # Unmount the dmg + self.update_task_label.emit(f"Unmounting /Volumes/Docker") + subprocess.run(["hdiutil", "detach", "/Volumes/Docker"]) + + self.install_finished.emit() + + except Exception as e: + self.install_failed.emit(str(e)) + return + + elif platform.system() == "Windows": + try: + # Run the installer + subprocess.run([self.installer_filename]) + self.install_finished.emit() + + except Exception as e: + self.install_failed.emit(str(e)) + return - except Exception as e: - self.install_failed.emit(str(e)) - return From 8974afa2b525e75d3f79ec53cb986036c62fc339 Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Wed, 12 Feb 2020 16:50:21 -0800 Subject: [PATCH 02/10] Working on making pyinstaller work for Windows as well as Mac, sharing the same pyinstaller.spec --- BUILD.md | 92 ++++++++++++ Pipfile | 11 +- Pipfile.lock | 32 +++- install/macos/build_app.py | 2 +- install/macos/pyinstaller.spec | 159 -------------------- install/{macos => pyinstaller}/dangerzone | 0 install/pyinstaller/pyinstaller.spec | 171 ++++++++++++++++++++++ 7 files changed, 299 insertions(+), 168 deletions(-) delete mode 100644 install/macos/pyinstaller.spec rename install/{macos => pyinstaller}/dangerzone (100%) create mode 100644 install/pyinstaller/pyinstaller.spec diff --git a/BUILD.md b/BUILD.md index c5c91d7..60a85ec 100644 --- a/BUILD.md +++ b/BUILD.md @@ -87,3 +87,95 @@ After that you can launch GPG Sync during development with: ``` python -m pipenv run python dev_scripts\dangerzone ``` + +### If you want to build a .exe + +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 and install the [Windows 10 SDK](https://developer.microsoft.com/en-US/windows/downloads/windows-10-sdk/). + +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` + +### If you want the .exe to not get falsely flagged as malicious by anti-virus software + +Dangerzone uses PyInstaller to turn the python source code into Windows executable `.exe` file. Apparently, malware developers also use PyInstaller, and some anti-virus vendors have included snippets of PyInstaller code in their virus definitions. To avoid this, you have to compile the Windows PyInstaller bootloader yourself instead of using the pre-compiled one that comes with PyInstaller. + +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. + +Then, enable the 32-bit Visual C++ Toolset on the Command Line like this: + +``` +cd "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build" +vcvars32.bat +``` + +Change to a folder where you keep source code, and clone the PyInstaller git repo and checkout the `v3.6` tag: + +``` +git clone https://github.com/pyinstaller/pyinstaller.git +cd pyinstaller +git tag -v v3.6 +``` + +(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).) + +The next step is to compile the bootloader. We should do this all in dangerzone's pipenv though: + +``` +cd dangerzone +pipenv shell +cd ..\pyinstaller +``` + +Then, compile the bootloader: + +``` +cd bootloader +python waf distclean all --target-arch=32bit --msvc_targets=x86 +``` + +Finally, install the PyInstaller module into your pipenv: + +``` +python setup.py install +exit +``` + +Now the next time you use PyInstaller to build GPG Sync, the `.exe` file should not be flagged as malicious by anti-virus. + +### If you want to build the installer + +* Go to http://nsis.sourceforge.net/Download and download the latest NSIS. I downloaded `nsis-3.05-setup.exe`. +* Add `C:\Program Files (x86)\NSIS` to the path. + +### If you want to sign binaries with Authenticode + +* You'll need a code signing certificate. I got an open source code signing certificate from [Certum](https://www.certum.eu/certum/cert,offer_en_open_source_cs.xml). +* Once you get a code signing key and certificate and covert it to a pfx file, import it into your certificate store. + +## To make a .exe + +Open a command prompt, cd into the dangerzone directory, and run: + +``` +pipenv run pyinstaller install\pyinstaller\pyinstaller.spec +``` + +`dangerzone.exe` and all of their supporting files will get created inside the `dist` folder. + +### To build the installer + +Note that you must have a codesigning certificate installed in order to use the `install\windows\build_exe.bat` script, because it codesigns `dangerzone.exe`, `uninstall.exe`, and `dangerzone-setup.exe`. + +Open a command prompt, cd to the dangerzone directory, and run: + +``` +pipenv run install\build_exe.bat +``` + +This will prompt you to codesign three binaries and execute one unsigned binary. When you're done clicking through everything you will have `dist\dangerzone-setup.exe`. \ No newline at end of file diff --git a/Pipfile b/Pipfile index 0ac87f2..9514a74 100644 --- a/Pipfile +++ b/Pipfile @@ -7,14 +7,17 @@ name = "pypi" PyQt5 = "*" click = "*" appdirs = "*" -pyxdg = {version = "*",platform_system = "== 'Linux'"} -pyobjc-core = {version = "*",platform_system = "== 'Darwin'"} -pyobjc-framework-launchservices = {version = "*",platform_system = "== 'Darwin'"} requests = "*" +pyxdg = {version = "*",sys_platform = "== 'linux'"} +pyobjc-core = {version = "*",sys_platform = "== 'darwin'"} +pyobjc-framework-launchservices = {version = "*",sys_platform = "== 'darwin'"} [dev-packages] black = "*" -pyinstaller = "*" +# Windows pyinstaller we build from source +pyinstaller = {version = "*",sys_platform = "== 'darwin'"} +setuptools = {version = "*",sys_platform = "== 'win32'"} +pywin32 = {version = "*",sys_platform = "== 'win32'"} [requires] python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock index 87570ae..fa6c48c 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "695116394343f7849640651aff1c6957762111bbe2905e3e4d4473be4d6dfb43" + "sha256": "89bd5b1770c4cab967141570476976c60d97ce9949d9cb5431bef3034aa98a6f" }, "pipfile-spec": 6, "requires": { @@ -61,7 +61,7 @@ "sha256:8ccf44511cbe438fa6562c423c0c5f1dad7cfc0eadd6d8f112840f8845b44fda" ], "index": "pypi", - "markers": "platform_system == 'Darwin'", + "markers": "sys_platform == 'darwin'", "version": "==6.1" }, "pyobjc-framework-cocoa": { @@ -97,7 +97,7 @@ "sha256:944b8ce7fb4215019bb55bd48b46685032d8db3fc2ff8cd80dfe56356cd99fd2" ], "index": "pypi", - "markers": "platform_system == 'Darwin'", + "markers": "sys_platform == 'darwin'", "version": "==6.1" }, "pyqt5": { @@ -139,7 +139,7 @@ "sha256:fe2928d3f532ed32b39c32a482b54136fe766d19936afc96c8f00645f9da1a06" ], "index": "pypi", - "markers": "platform_system == 'Linux'", + "markers": "sys_platform == 'linux'", "version": "==0.26" }, "requests": { @@ -216,8 +216,28 @@ "sha256:3730fa80d088f8bb7084d32480eb87cbb4ddb64123363763cf8f2a1378c1c4b7" ], "index": "pypi", + "markers": "sys_platform == 'darwin'", "version": "==3.6" }, + "pywin32": { + "hashes": [ + "sha256:300a2db938e98c3e7e2093e4491439e62287d0d493fe07cce110db070b54c0be", + "sha256:31f88a89139cb2adc40f8f0e65ee56a8c585f629974f9e07622ba80199057511", + "sha256:371fcc39416d736401f0274dd64c2302728c9e034808e37381b5e1b22be4a6b0", + "sha256:47a3c7551376a865dd8d095a98deba954a98f326c6fe3c72d8726ca6e6b15507", + "sha256:4cdad3e84191194ea6d0dd1b1b9bdda574ff563177d2adf2b4efec2a244fa116", + "sha256:7c1ae32c489dc012930787f06244426f8356e129184a02c25aef163917ce158e", + "sha256:7f18199fbf29ca99dff10e1f09451582ae9e372a892ff03a28528a24d55875bc", + "sha256:9b31e009564fb95db160f154e2aa195ed66bcc4c058ed72850d047141b36f3a2", + "sha256:a929a4af626e530383a579431b70e512e736e9588106715215bf685a3ea508d4", + "sha256:c054c52ba46e7eb6b7d7dfae4dbd987a1bb48ee86debe3f245a2884ece46e295", + "sha256:f27cec5e7f588c3d1051651830ecc00294f90728d19c3bf6916e6dba93ea357c", + "sha256:f4c5be1a293bae0076d93c88f37ee8da68136744588bc5e2be2f299a34ceb7aa" + ], + "index": "pypi", + "markers": "sys_platform == 'win32'", + "version": "==227" + }, "regex": { "hashes": [ "sha256:07b39bf943d3d2fe63d46281d8504f8df0ff3fe4c57e13d1656737950e53e525", @@ -244,6 +264,10 @@ ], "version": "==2020.1.8" }, + "setuptools": { + "sys_platform": "== 'win32'", + "version": "*" + }, "toml": { "hashes": [ "sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c", diff --git a/install/macos/build_app.py b/install/macos/build_app.py index 20d0410..b0e7bbb 100755 --- a/install/macos/build_app.py +++ b/install/macos/build_app.py @@ -40,7 +40,7 @@ def main(): shutil.rmtree(dist_path) print("○ Building app bundle") - run(["pyinstaller", "install/macos/pyinstaller.spec", "--clean"]) + run(["pyinstaller", "install/pyinstaller/pyinstaller.spec", "--clean"]) shutil.rmtree(os.path.join(dist_path, "dangerzone")) print(f"○ Finished build app: {app_path}") diff --git a/install/macos/pyinstaller.spec b/install/macos/pyinstaller.spec deleted file mode 100644 index e5f3e26..0000000 --- a/install/macos/pyinstaller.spec +++ /dev/null @@ -1,159 +0,0 @@ -# -*- mode: python -*- -import sys -import os -import inspect - -# Get the version -root = os.path.dirname( - os.path.dirname( - os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) - ) -) -sys.path.insert(0, root) -import dangerzone - -version = dangerzone.dangerzone_version -print("Flock Agent version: {}".format(version)) - -a = Analysis( - ["dangerzone"], - pathex=["."], - binaries=None, - datas=[("../../share", "share"), ("document.icns", ".")], - hiddenimports=[], - hookspath=[], - runtime_hooks=[], - excludes=[], - win_no_prefer_redirects=False, - win_private_assemblies=False, - cipher=None, -) - -pyz = PYZ(a.pure, a.zipped_data, cipher=None) - -exe = EXE( - pyz, - a.scripts, - exclude_binaries=True, - name="dangerzone", - debug=False, - strip=False, - upx=True, - console=False, -) - -coll = COLLECT( - exe, a.binaries, a.zipfiles, a.datas, strip=False, upx=True, name="dangerzone" -) - -app = BUNDLE( - coll, - name="Dangerzone.app", - icon="dangerzone.icns", - bundle_identifier="media.firstlook.dangerzone", - info_plist={ - "NSHighResolutionCapable": True, - "CFBundleShortVersionString": version, - "CFBundleDocumentTypes": [ - { - "CFBundleTypeExtensions": ["pdf"], - "CFBundleTypeIconFile": "document.icns", - "CFBundleTypeMIMETypes": ["application/pdf"], - "CFBundleTypeName": "PDF Document", - "CFBundleTypeRole": "Viewer", - }, - { - "CFBundleTypeExtensions": ["docx", "doc"], - "CFBundleTypeIconFile": "document.icns", - "CFBundleTypeMIMETypes": [ - "application/vnd.openxmlformats-officedocument.wordprocessingml.document", - "application/msword", - ], - "CFBundleTypeName": "Microsoft Word Document", - "CFBundleTypeRole": "Viewer", - }, - { - "CFBundleTypeExtensions": ["xlsx", "xls"], - "CFBundleTypeIconFile": "document.icns", - "CFBundleTypeMIMETypes": [ - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - "application/vnd.ms-excel", - ], - "CFBundleTypeName": "Microsoft Excel Document", - "CFBundleTypeRole": "Viewer", - }, - { - "CFBundleTypeExtensions": ["pptx", "ppt"], - "CFBundleTypeIconFile": "document.icns", - "CFBundleTypeMIMETypes": [ - "application/vnd.openxmlformats-officedocument.presentationml.presentation", - "application/vnd.ms-powerpoint", - ], - "CFBundleTypeName": "Microsoft PowerPoint Document", - "CFBundleTypeRole": "Viewer", - }, - { - "CFBundleTypeExtensions": ["odg"], - "CFBundleTypeIconFile": "document.icns", - "CFBundleTypeMIMETypes": ["application/vnd.oasis.opendocument.text"], - "CFBundleTypeName": "ODF Text Document", - "CFBundleTypeRole": "Viewer", - }, - { - "CFBundleTypeExtensions": ["ops"], - "CFBundleTypeIconFile": "document.icns", - "CFBundleTypeMIMETypes": [ - "application/vnd.oasis.opendocument.spreadsheet" - ], - "CFBundleTypeName": "ODF Spreadsheet Document", - "CFBundleTypeRole": "Viewer", - }, - { - "CFBundleTypeExtensions": ["odp"], - "CFBundleTypeIconFile": "document.icns", - "CFBundleTypeMIMETypes": [ - "application/vnd.oasis.opendocument.presentation" - ], - "CFBundleTypeName": "ODF Presentation Document", - "CFBundleTypeRole": "Viewer", - }, - { - "CFBundleTypeExtensions": ["odg"], - "CFBundleTypeIconFile": "document.icns", - "CFBundleTypeMIMETypes": [ - "application/vnd.oasis.opendocument.graphics" - ], - "CFBundleTypeName": "ODF Graphics Document", - "CFBundleTypeRole": "Viewer", - }, - { - "CFBundleTypeExtensions": ["jpg", "jpeg"], - "CFBundleTypeIconFile": "document.icns", - "CFBundleTypeMIMETypes": ["image/jpeg"], - "CFBundleTypeName": "JPEG Image", - "CFBundleTypeRole": "Viewer", - }, - { - "CFBundleTypeExtensions": ["gif"], - "CFBundleTypeIconFile": "document.icns", - "CFBundleTypeMIMETypes": ["image/gif"], - "CFBundleTypeName": "GIF Image", - "CFBundleTypeRole": "Viewer", - }, - { - "CFBundleTypeExtensions": ["png"], - "CFBundleTypeIconFile": "document.icns", - "CFBundleTypeMIMETypes": ["image/png"], - "CFBundleTypeName": "PNG Image", - "CFBundleTypeRole": "Viewer", - }, - { - "CFBundleTypeExtensions": ["tif", "tiff"], - "CFBundleTypeIconFile": "document.icns", - "CFBundleTypeMIMETypes": ["image/tiff", "image/x-tiff"], - "CFBundleTypeName": "TIFF Image", - "CFBundleTypeRole": "Viewer", - }, - ], - }, -) diff --git a/install/macos/dangerzone b/install/pyinstaller/dangerzone similarity index 100% rename from install/macos/dangerzone rename to install/pyinstaller/dangerzone diff --git a/install/pyinstaller/pyinstaller.spec b/install/pyinstaller/pyinstaller.spec new file mode 100644 index 0000000..41944fa --- /dev/null +++ b/install/pyinstaller/pyinstaller.spec @@ -0,0 +1,171 @@ +# -*- mode: python -*- +import sys +import os +import inspect +import platform + +p = platform.system() + +# Get the version +root = os.path.dirname( + os.path.dirname( + os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) + ) +) +sys.path.insert(0, root) +import dangerzone + +version = dangerzone.dangerzone_version +print("Flock Agent version: {}".format(version)) + +if p == "Darwin": + datas = [("../../share", "share"), ("../macos/document.icns", ".")] +else: + datas = [("../../share", "share")] + +a = Analysis( + ["dangerzone"], + pathex=["."], + binaries=None, + datas=datas, + hiddenimports=[], + hookspath=[], + runtime_hooks=[], + excludes=[], + win_no_prefer_redirects=False, + win_private_assemblies=False, + cipher=None, +) + +pyz = PYZ(a.pure, a.zipped_data, cipher=None) + +exe = EXE( + pyz, + a.scripts, + exclude_binaries=True, + name="dangerzone", + debug=False, + strip=False, + upx=True, + console=False, +) + +coll = COLLECT( + exe, a.binaries, a.zipfiles, a.datas, strip=False, upx=True, name="dangerzone" +) + +# The macOS app bundle +if p == "Darwin": + app = BUNDLE( + coll, + name="Dangerzone.app", + icon="dangerzone.icns", + bundle_identifier="media.firstlook.dangerzone", + info_plist={ + "NSHighResolutionCapable": True, + "CFBundleShortVersionString": version, + "CFBundleDocumentTypes": [ + { + "CFBundleTypeExtensions": ["pdf"], + "CFBundleTypeIconFile": "document.icns", + "CFBundleTypeMIMETypes": ["application/pdf"], + "CFBundleTypeName": "PDF Document", + "CFBundleTypeRole": "Viewer", + }, + { + "CFBundleTypeExtensions": ["docx", "doc"], + "CFBundleTypeIconFile": "document.icns", + "CFBundleTypeMIMETypes": [ + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + "application/msword", + ], + "CFBundleTypeName": "Microsoft Word Document", + "CFBundleTypeRole": "Viewer", + }, + { + "CFBundleTypeExtensions": ["xlsx", "xls"], + "CFBundleTypeIconFile": "document.icns", + "CFBundleTypeMIMETypes": [ + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + "application/vnd.ms-excel", + ], + "CFBundleTypeName": "Microsoft Excel Document", + "CFBundleTypeRole": "Viewer", + }, + { + "CFBundleTypeExtensions": ["pptx", "ppt"], + "CFBundleTypeIconFile": "document.icns", + "CFBundleTypeMIMETypes": [ + "application/vnd.openxmlformats-officedocument.presentationml.presentation", + "application/vnd.ms-powerpoint", + ], + "CFBundleTypeName": "Microsoft PowerPoint Document", + "CFBundleTypeRole": "Viewer", + }, + { + "CFBundleTypeExtensions": ["odg"], + "CFBundleTypeIconFile": "document.icns", + "CFBundleTypeMIMETypes": [ + "application/vnd.oasis.opendocument.text" + ], + "CFBundleTypeName": "ODF Text Document", + "CFBundleTypeRole": "Viewer", + }, + { + "CFBundleTypeExtensions": ["ops"], + "CFBundleTypeIconFile": "document.icns", + "CFBundleTypeMIMETypes": [ + "application/vnd.oasis.opendocument.spreadsheet" + ], + "CFBundleTypeName": "ODF Spreadsheet Document", + "CFBundleTypeRole": "Viewer", + }, + { + "CFBundleTypeExtensions": ["odp"], + "CFBundleTypeIconFile": "document.icns", + "CFBundleTypeMIMETypes": [ + "application/vnd.oasis.opendocument.presentation" + ], + "CFBundleTypeName": "ODF Presentation Document", + "CFBundleTypeRole": "Viewer", + }, + { + "CFBundleTypeExtensions": ["odg"], + "CFBundleTypeIconFile": "document.icns", + "CFBundleTypeMIMETypes": [ + "application/vnd.oasis.opendocument.graphics" + ], + "CFBundleTypeName": "ODF Graphics Document", + "CFBundleTypeRole": "Viewer", + }, + { + "CFBundleTypeExtensions": ["jpg", "jpeg"], + "CFBundleTypeIconFile": "document.icns", + "CFBundleTypeMIMETypes": ["image/jpeg"], + "CFBundleTypeName": "JPEG Image", + "CFBundleTypeRole": "Viewer", + }, + { + "CFBundleTypeExtensions": ["gif"], + "CFBundleTypeIconFile": "document.icns", + "CFBundleTypeMIMETypes": ["image/gif"], + "CFBundleTypeName": "GIF Image", + "CFBundleTypeRole": "Viewer", + }, + { + "CFBundleTypeExtensions": ["png"], + "CFBundleTypeIconFile": "document.icns", + "CFBundleTypeMIMETypes": ["image/png"], + "CFBundleTypeName": "PNG Image", + "CFBundleTypeRole": "Viewer", + }, + { + "CFBundleTypeExtensions": ["tif", "tiff"], + "CFBundleTypeIconFile": "document.icns", + "CFBundleTypeMIMETypes": ["image/tiff", "image/x-tiff"], + "CFBundleTypeName": "TIFF Image", + "CFBundleTypeRole": "Viewer", + }, + ], + }, + ) From 400b8d2b8312866170f2c7dfbff74087655fd1ae Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Thu, 13 Feb 2020 10:21:11 -0800 Subject: [PATCH 03/10] Switch from pipenv to poetry, which has better cross-platform support --- BUILD.md | 48 +++--- Pipfile | 26 --- Pipfile.lock | 305 -------------------------------- poetry.lock | 460 +++++++++++++++++++++++++++++++++++++++++++++++++ pyproject.toml | 27 +++ 5 files changed, 514 insertions(+), 352 deletions(-) delete mode 100644 Pipfile delete mode 100644 Pipfile.lock create mode 100644 poetry.lock create mode 100644 pyproject.toml diff --git a/BUILD.md b/BUILD.md index 60a85ec..8489947 100644 --- a/BUILD.md +++ b/BUILD.md @@ -37,22 +37,22 @@ Download and install Python 3.7.4 from https://www.python.org/downloads/release/ 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 pipenv (`pip3 install --user pipenv`). Then install dependencies: +If you don't have it already, install poetry (`pip3 install --user poetry`). Then install dependencies: ```sh -pipenv install --dev --pre +poetry install ``` Run from source tree: ``` -pipenv run ./dev_scripts/dangerzone +poetry run ./dev_scripts/dangerzone ``` To create an app bundle and DMG for distribution, use the `build_app.py` script ```sh -pipenv run ./install/macos/build_app.py +poetry run ./install/macos/build_app.py ``` If you want to build for distribution, you'll need a codesigning certificate, and you'll also need to have [create-dmg](https://github.com/sindresorhus/create-dmg) installed: @@ -65,33 +65,39 @@ brew install graphicsmagick imagemagick And then run `build_app.py --with-codesign`: ```sh -pipenv run ./install/macos/build_app.py --with-codesign +poetry run ./install/macos/build_app.py --with-codesign ``` The output is in the `dist` folder. ## Windows +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. -Open a command prompt and cd to the gpgsync folder. If you don't have it already, install pipenv (`pip install pipenv`). Then install dependencies: - -``` -python -m pipenv install --dev -``` - 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`. -After that you can launch GPG Sync during development with: +Install [poetry](https://python-poetry.org/). Open PowerShell, and run: ``` -python -m pipenv run python dev_scripts\dangerzone +(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: + +``` +poetry install +``` + +After that you can launch dangerzone during development with: + +``` +poetry run python dev_scripts\dangerzone ``` ### If you want to build a .exe -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 and install the [Windows 10 SDK](https://developer.microsoft.com/en-US/windows/downloads/windows-10-sdk/). Add the following directories to the path: @@ -124,11 +130,11 @@ git tag -v v3.6 (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).) -The next step is to compile the bootloader. We should do this all in dangerzone's pipenv though: +The next step is to compile the bootloader. We should do this all in dangerzone's poetry shell: ``` cd dangerzone -pipenv shell +poetry shell cd ..\pyinstaller ``` @@ -139,14 +145,14 @@ cd bootloader python waf distclean all --target-arch=32bit --msvc_targets=x86 ``` -Finally, install the PyInstaller module into your pipenv: +Finally, install the PyInstaller module into your poetry environment: ``` python setup.py install exit ``` -Now the next time you use PyInstaller to build GPG Sync, the `.exe` file should not be flagged as malicious by anti-virus. +Now the next time you use PyInstaller to build dangerzone, the `.exe` file should not be flagged as malicious by anti-virus. ### If you want to build the installer @@ -163,7 +169,7 @@ Now the next time you use PyInstaller to build GPG Sync, the `.exe` file should Open a command prompt, cd into the dangerzone directory, and run: ``` -pipenv run pyinstaller install\pyinstaller\pyinstaller.spec +poetry run pyinstaller install\pyinstaller\pyinstaller.spec ``` `dangerzone.exe` and all of their supporting files will get created inside the `dist` folder. @@ -175,7 +181,7 @@ Note that you must have a codesigning certificate installed in order to use the Open a command prompt, cd to the dangerzone directory, and run: ``` -pipenv run install\build_exe.bat +poetry run install\build_exe.bat ``` This will prompt you to codesign three binaries and execute one unsigned binary. When you're done clicking through everything you will have `dist\dangerzone-setup.exe`. \ No newline at end of file diff --git a/Pipfile b/Pipfile deleted file mode 100644 index 9514a74..0000000 --- a/Pipfile +++ /dev/null @@ -1,26 +0,0 @@ -[[source]] -url = "https://pypi.python.org/simple" -verify_ssl = true -name = "pypi" - -[packages] -PyQt5 = "*" -click = "*" -appdirs = "*" -requests = "*" -pyxdg = {version = "*",sys_platform = "== 'linux'"} -pyobjc-core = {version = "*",sys_platform = "== 'darwin'"} -pyobjc-framework-launchservices = {version = "*",sys_platform = "== 'darwin'"} - -[dev-packages] -black = "*" -# Windows pyinstaller we build from source -pyinstaller = {version = "*",sys_platform = "== 'darwin'"} -setuptools = {version = "*",sys_platform = "== 'win32'"} -pywin32 = {version = "*",sys_platform = "== 'win32'"} - -[requires] -python_version = "3.7" - -[pipenv] -allow_prereleases = true diff --git a/Pipfile.lock b/Pipfile.lock deleted file mode 100644 index fa6c48c..0000000 --- a/Pipfile.lock +++ /dev/null @@ -1,305 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "89bd5b1770c4cab967141570476976c60d97ce9949d9cb5431bef3034aa98a6f" - }, - "pipfile-spec": 6, - "requires": { - "python_version": "3.7" - }, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.python.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "appdirs": { - "hashes": [ - "sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92", - "sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e" - ], - "index": "pypi", - "version": "==1.4.3" - }, - "certifi": { - "hashes": [ - "sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3", - "sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f" - ], - "version": "==2019.11.28" - }, - "chardet": { - "hashes": [ - "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", - "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" - ], - "version": "==3.0.4" - }, - "click": { - "hashes": [ - "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", - "sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7" - ], - "index": "pypi", - "version": "==7.0" - }, - "idna": { - "hashes": [ - "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", - "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c" - ], - "version": "==2.8" - }, - "pyobjc-core": { - "hashes": [ - "sha256:1a0fbf012fb575e0adf8c18cfd4453e657cc2c0deb2660c529bf524ba4c9149a", - "sha256:470ccd754efb468a59426942673dfc3c5c59f33a5b8cae8a7fc1be975c2d4128", - "sha256:751cdeb436cb181af2e2413015b072075590577c410c7f345080a38dd028b8ec", - "sha256:8ccf44511cbe438fa6562c423c0c5f1dad7cfc0eadd6d8f112840f8845b44fda" - ], - "index": "pypi", - "markers": "sys_platform == 'darwin'", - "version": "==6.1" - }, - "pyobjc-framework-cocoa": { - "hashes": [ - "sha256:1dc428f867d35007ddf9de5b24eff5bfdf65c58b1d610abcb08bebd94c343312", - "sha256:245e19156739f8068db474ad9561079cc698f08ef525e299b8eedc5531e02801", - "sha256:32ba4d0ce811e2088bf0fc360c9545c06586934e895f7133655b8f2182e7019a", - "sha256:c4077d2e6f96e4f3fd9780d66778cf51d27f414822498b24410e9df7a6a4d531" - ], - "version": "==6.1" - }, - "pyobjc-framework-coreservices": { - "hashes": [ - "sha256:0e28004a6fcc3d8928d7c8ddac2059651847851e2bad7fe2d1ed7fd12615065c", - "sha256:416c47d12640ddcdb773eee6a99e09d26326dadb15056d0f7734eff913d4ce7b", - "sha256:665f979403ebae16b4d9945d24829c12c2aeccc0338cd04a268a324b6cc654a2", - "sha256:a2977e948027677fca574a6c3fc4654f6644700bf9d2afa87c64afa2acf4b66e" - ], - "version": "==6.1" - }, - "pyobjc-framework-fsevents": { - "hashes": [ - "sha256:3a403ce5997cc01f23f1a70f8b4c919311b9a6b1fdd3c3d02d19079d711f954c", - "sha256:7a635c86af744a1d17f0c6c3913bef87b5fd146e0311c03229eba9e512b81520", - "sha256:94c6953774b6d69e59d9781951f05ef57e352b3c530d4c236f463444852c3a88", - "sha256:d2ae8748d1791dc9e3d19b41d3873283ac34ed17ff8fca70f1a199336a0477b5" - ], - "version": "==6.1" - }, - "pyobjc-framework-launchservices": { - "hashes": [ - "sha256:1c1896f356e9c7ac6255863422565ed922589c10bba3dc2850729df666794346", - "sha256:944b8ce7fb4215019bb55bd48b46685032d8db3fc2ff8cd80dfe56356cd99fd2" - ], - "index": "pypi", - "markers": "sys_platform == 'darwin'", - "version": "==6.1" - }, - "pyqt5": { - "hashes": [ - "sha256:2d94ec761fb656707050c68b41958e3a9f755bb1df96c064470f4096d2899e32", - "sha256:2f230f2dbd767099de7a0cb915abdf0cbc3256a0b5bb910eb09b99117db7a65b", - "sha256:31b142a868152d60c6323e0527edb692fdf05fd7cb4fe2fe9ce07d1ce560221a", - "sha256:713b9a201f5e7b2fca8691373e5d5c8c2552a51d87ca9ffbb1461e34e3241211", - "sha256:a0bfe9fd718bca4de3e33000347e048f73126b6dc46530eb020b0251a638ee9d" - ], - "index": "pypi", - "version": "==5.14.1" - }, - "pyqt5-sip": { - "hashes": [ - "sha256:1115728644bbadcde5fc8a16e7918bd31915a42dd6fb36b10d4afb78c582753e", - "sha256:1f4289276d355b6521dc2cc956189315da6f13adfb6bbab8f25ebd15e3bce1d4", - "sha256:288c6dc18a8d6a20981c07b715b5695d9b66880778565f3792bc6e38f14f20fb", - "sha256:3f665376d9e52faa9855c3736a66ce6d825f85c86d7774d3c393f09da23f4f86", - "sha256:6b4860c4305980db509415d0af802f111d15f92016c9422eb753bc8883463456", - "sha256:7ffa39763097f64de129cf5cc770a651c3f65d2466b4fe05bef2bd2efbaa38e6", - "sha256:8a18e6f45d482ddfe381789979d09ee13aa6450caa3a0476503891bccb3ac709", - "sha256:8da842d3d7bf8931d1093105fb92702276b6dbb7e801abbaaa869405d616171a", - "sha256:b42021229424aa44e99b3b49520b799fd64ff6ae8b53f79f903bbd85719a28e4", - "sha256:b5b4906445fe980aee76f20400116b6904bf5f30d0767489c13370e42a764020", - "sha256:c1e730a9eb2ec3869ed5d81b0f99f6e2460fb4d77750444c0ec183b771d798f7", - "sha256:cbeeae6b45234a1654657f79943f8bccd3d14b4e7496746c62cf6fbce69442c7", - "sha256:d46b0f8effc554de52a1466b1bd80e5cb4bce635a75ac4e7ad6247c965dec5b9", - "sha256:e28c3abc9b62a1b7e796891648b9f14f8167b31c8e7990fae79654777252bb4d", - "sha256:e6078f5ee7d31c102910d0c277a110e1c2a20a3fc88cd017a39e170120586d3f", - "sha256:ee1a12f09d5af2304273bfd2f6b43835c1467d5ed501a6c95f5405637fa7750a", - "sha256:f314f31f5fd39b06897f013f425137e511d45967150eb4e424a363d8138521c6" - ], - "version": "==12.7.1" - }, - "pyxdg": { - "hashes": [ - "sha256:1948ff8e2db02156c0cccd2529b43c0cff56ebaa71f5f021bbd755bc1419190e", - "sha256:fe2928d3f532ed32b39c32a482b54136fe766d19936afc96c8f00645f9da1a06" - ], - "index": "pypi", - "markers": "sys_platform == 'linux'", - "version": "==0.26" - }, - "requests": { - "hashes": [ - "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4", - "sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31" - ], - "index": "pypi", - "version": "==2.22.0" - }, - "urllib3": { - "hashes": [ - "sha256:2f3db8b19923a873b3e5256dc9c2dedfa883e33d87c690d9c7913e1f40673cdc", - "sha256:87716c2d2a7121198ebcb7ce7cccf6ce5e9ba539041cfbaeecfb641dc0bf6acc" - ], - "version": "==1.25.8" - } - }, - "develop": { - "altgraph": { - "hashes": [ - "sha256:1f05a47122542f97028caf78775a095fbe6a2699b5089de8477eb583167d69aa", - "sha256:c623e5f3408ca61d4016f23a681b9adb100802ca3e3da5e718915a9e4052cebe" - ], - "version": "==0.17" - }, - "appdirs": { - "hashes": [ - "sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92", - "sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e" - ], - "index": "pypi", - "version": "==1.4.3" - }, - "attrs": { - "hashes": [ - "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c", - "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72" - ], - "version": "==19.3.0" - }, - "black": { - "hashes": [ - "sha256:1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b", - "sha256:c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539" - ], - "index": "pypi", - "version": "==19.10b0" - }, - "click": { - "hashes": [ - "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", - "sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7" - ], - "index": "pypi", - "version": "==7.0" - }, - "macholib": { - "hashes": [ - "sha256:0c436bc847e7b1d9bda0560351bf76d7caf930fb585a828d13608839ef42c432", - "sha256:c500f02867515e6c60a27875b408920d18332ddf96b4035ef03beddd782d4281" - ], - "version": "==1.14" - }, - "pathspec": { - "hashes": [ - "sha256:163b0632d4e31cef212976cf57b43d9fd6b0bac6e67c26015d611a647d5e7424", - "sha256:562aa70af2e0d434367d9790ad37aed893de47f1693e4201fd1d3dca15d19b96" - ], - "version": "==0.7.0" - }, - "pyinstaller": { - "hashes": [ - "sha256:3730fa80d088f8bb7084d32480eb87cbb4ddb64123363763cf8f2a1378c1c4b7" - ], - "index": "pypi", - "markers": "sys_platform == 'darwin'", - "version": "==3.6" - }, - "pywin32": { - "hashes": [ - "sha256:300a2db938e98c3e7e2093e4491439e62287d0d493fe07cce110db070b54c0be", - "sha256:31f88a89139cb2adc40f8f0e65ee56a8c585f629974f9e07622ba80199057511", - "sha256:371fcc39416d736401f0274dd64c2302728c9e034808e37381b5e1b22be4a6b0", - "sha256:47a3c7551376a865dd8d095a98deba954a98f326c6fe3c72d8726ca6e6b15507", - "sha256:4cdad3e84191194ea6d0dd1b1b9bdda574ff563177d2adf2b4efec2a244fa116", - "sha256:7c1ae32c489dc012930787f06244426f8356e129184a02c25aef163917ce158e", - "sha256:7f18199fbf29ca99dff10e1f09451582ae9e372a892ff03a28528a24d55875bc", - "sha256:9b31e009564fb95db160f154e2aa195ed66bcc4c058ed72850d047141b36f3a2", - "sha256:a929a4af626e530383a579431b70e512e736e9588106715215bf685a3ea508d4", - "sha256:c054c52ba46e7eb6b7d7dfae4dbd987a1bb48ee86debe3f245a2884ece46e295", - "sha256:f27cec5e7f588c3d1051651830ecc00294f90728d19c3bf6916e6dba93ea357c", - "sha256:f4c5be1a293bae0076d93c88f37ee8da68136744588bc5e2be2f299a34ceb7aa" - ], - "index": "pypi", - "markers": "sys_platform == 'win32'", - "version": "==227" - }, - "regex": { - "hashes": [ - "sha256:07b39bf943d3d2fe63d46281d8504f8df0ff3fe4c57e13d1656737950e53e525", - "sha256:0932941cdfb3afcbc26cc3bcf7c3f3d73d5a9b9c56955d432dbf8bbc147d4c5b", - "sha256:0e182d2f097ea8549a249040922fa2b92ae28be4be4895933e369a525ba36576", - "sha256:10671601ee06cf4dc1bc0b4805309040bb34c9af423c12c379c83d7895622bb5", - "sha256:23e2c2c0ff50f44877f64780b815b8fd2e003cda9ce817a7fd00dea5600c84a0", - "sha256:26ff99c980f53b3191d8931b199b29d6787c059f2e029b2b0c694343b1708c35", - "sha256:27429b8d74ba683484a06b260b7bb00f312e7c757792628ea251afdbf1434003", - "sha256:3e77409b678b21a056415da3a56abfd7c3ad03da71f3051bbcdb68cf44d3c34d", - "sha256:4e8f02d3d72ca94efc8396f8036c0d3bcc812aefc28ec70f35bb888c74a25161", - "sha256:4eae742636aec40cf7ab98171ab9400393360b97e8f9da67b1867a9ee0889b26", - "sha256:6a6ae17bf8f2d82d1e8858a47757ce389b880083c4ff2498dba17c56e6c103b9", - "sha256:6a6ba91b94427cd49cd27764679024b14a96874e0dc638ae6bdd4b1a3ce97be1", - "sha256:7bcd322935377abcc79bfe5b63c44abd0b29387f267791d566bbb566edfdd146", - "sha256:98b8ed7bb2155e2cbb8b76f627b2fd12cf4b22ab6e14873e8641f266e0fb6d8f", - "sha256:bd25bb7980917e4e70ccccd7e3b5740614f1c408a642c245019cff9d7d1b6149", - "sha256:d0f424328f9822b0323b3b6f2e4b9c90960b24743d220763c7f07071e0778351", - "sha256:d58e4606da2a41659c84baeb3cfa2e4c87a74cec89a1e7c56bee4b956f9d7461", - "sha256:e3cd21cc2840ca67de0bbe4071f79f031c81418deb544ceda93ad75ca1ee9f7b", - "sha256:e6c02171d62ed6972ca8631f6f34fa3281d51db8b326ee397b9c83093a6b7242", - "sha256:e7c7661f7276507bce416eaae22040fd91ca471b5b33c13f8ff21137ed6f248c", - "sha256:ecc6de77df3ef68fee966bb8cb4e067e84d4d1f397d0ef6fce46913663540d77" - ], - "version": "==2020.1.8" - }, - "setuptools": { - "sys_platform": "== 'win32'", - "version": "*" - }, - "toml": { - "hashes": [ - "sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c", - "sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e" - ], - "version": "==0.10.0" - }, - "typed-ast": { - "hashes": [ - "sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355", - "sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919", - "sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa", - "sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652", - "sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75", - "sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01", - "sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d", - "sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1", - "sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907", - "sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c", - "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3", - "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b", - "sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614", - "sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb", - "sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b", - "sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41", - "sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6", - "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34", - "sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe", - "sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4", - "sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7" - ], - "version": "==1.4.1" - } - } -} diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..843ce48 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,460 @@ +[[package]] +category = "main" +description = "Python graph (network) package" +name = "altgraph" +optional = false +python-versions = "*" +version = "0.17" + +[[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.3" + +[[package]] +category = "dev" +description = "Classes Without Boilerplate" +name = "attrs" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "19.3.0" + +[package.extras] +azure-pipelines = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "pytest-azurepipelines"] +dev = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "pre-commit"] +docs = ["sphinx", "zope.interface"] +tests = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] + +[[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]] +category = "main" +description = "Python package for providing Mozilla's CA Bundle." +name = "certifi" +optional = false +python-versions = "*" +version = "2019.11.28" + +[[package]] +category = "main" +description = "Universal encoding detector for Python 2 and 3" +name = "chardet" +optional = false +python-versions = "*" +version = "3.0.4" + +[[package]] +category = "main" +description = "Composable command line interface toolkit" +name = "click" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "7.0" + +[[package]] +category = "dev" +description = "Python 2.7 backport of the \"dis\" module from Python 3.5+" +marker = "sys_platform == \"darwin\"" +name = "dis3" +optional = false +python-versions = "*" +version = "0.1.3" + +[[package]] +category = "main" +description = "Internationalized Domain Names in Applications (IDNA)" +name = "idna" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "2.8" + +[[package]] +category = "main" +description = "Mach-O header analysis and editing" +name = "macholib" +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.7.0" + +[[package]] +category = "dev" +description = "PyInstaller bundles a Python application and all its dependencies into a single package." +marker = "sys_platform == \"darwin\"" +name = "pyinstaller" +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" +optional = false +python-versions = ">=3.6" +version = "6.1" + +[[package]] +category = "main" +description = "Wrappers for the Cocoa frameworks on macOS" +marker = "sys_platform == \"darwin\"" +name = "pyobjc-framework-cocoa" +optional = false +python-versions = ">=3.6" +version = "6.1" + +[package.dependencies] +pyobjc-core = ">=6.1" + +[[package]] +category = "main" +description = "Wrappers for the framework CoreServices on macOS" +marker = "sys_platform == \"darwin\"" +name = "pyobjc-framework-coreservices" +optional = false +python-versions = ">=3.6" +version = "6.1" + +[package.dependencies] +pyobjc-core = ">=6.1" +pyobjc-framework-FSEvents = ">=6.1" + +[[package]] +category = "main" +description = "Wrappers for the framework FSEvents on macOS" +marker = "sys_platform == \"darwin\"" +name = "pyobjc-framework-fsevents" +optional = false +python-versions = ">=3.6" +version = "6.1" + +[package.dependencies] +pyobjc-core = ">=6.1" +pyobjc-framework-Cocoa = ">=6.1" + +[[package]] +category = "main" +description = "Wrappers for the framework LaunchServices on macOS" +marker = "sys_platform == \"darwin\"" +name = "pyobjc-framework-launchservices" +optional = false +python-versions = ">=3.6" +version = "6.1" + +[package.dependencies] +pyobjc-core = ">=6.1" +pyobjc-framework-CoreServices = ">=6.1" + +[[package]] +category = "main" +description = "Python bindings for the Qt cross platform application toolkit" +name = "pyqt5" +optional = false +python-versions = ">=3.5" +version = "5.14.1" + +[package.dependencies] +PyQt5-sip = ">=12.7,<13" + +[[package]] +category = "main" +description = "The sip module support for PyQt5" +name = "pyqt5-sip" +optional = false +python-versions = ">=3.5" +version = "12.7.1" + +[[package]] +category = "main" +description = "Python for Window Extensions" +marker = "sys_platform == \"win32\"" +name = "pywin32" +optional = false +python-versions = "*" +version = "227" + +[[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" +optional = false +python-versions = "*" +version = "2020.1.8" + +[[package]] +category = "main" +description = "Python HTTP for Humans." +name = "requests" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "2.22.0" + +[package.dependencies] +certifi = ">=2017.4.17" +chardet = ">=3.0.2,<3.1.0" +idna = ">=2.5,<2.9" +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)", "idna (>=2.0.0)"] +socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7)", "win-inet-pton"] + +[[package]] +category = "dev" +description = "Python Library for Tom's Obvious, Minimal Language" +name = "toml" +optional = false +python-versions = "*" +version = "0.10.0" + +[[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]] +category = "main" +description = "HTTP library with thread-safe connection pooling, file post, and more." +name = "urllib3" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" +version = "1.25.8" + +[package.extras] +brotli = ["brotlipy (>=0.6.0)"] +secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] +socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"] + +[metadata] +content-hash = "1a7f436898ad10813c8bd4f2a4e12064e2777265bbd91616b00a997638a68e16" +python-versions = "^3.7" + +[metadata.files] +altgraph = [ + {file = "altgraph-0.17-py2.py3-none-any.whl", hash = "sha256:c623e5f3408ca61d4016f23a681b9adb100802ca3e3da5e718915a9e4052cebe"}, + {file = "altgraph-0.17.tar.gz", hash = "sha256:1f05a47122542f97028caf78775a095fbe6a2699b5089de8477eb583167d69aa"}, +] +appdirs = [ + {file = "appdirs-1.4.3-py2.py3-none-any.whl", hash = "sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e"}, + {file = "appdirs-1.4.3.tar.gz", hash = "sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92"}, +] +attrs = [ + {file = "attrs-19.3.0-py2.py3-none-any.whl", hash = "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c"}, + {file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"}, +] +black = [ + {file = "black-19.10b0-py36-none-any.whl", hash = "sha256:1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b"}, + {file = "black-19.10b0.tar.gz", hash = "sha256:c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539"}, +] +certifi = [ + {file = "certifi-2019.11.28-py2.py3-none-any.whl", hash = "sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3"}, + {file = "certifi-2019.11.28.tar.gz", hash = "sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f"}, +] +chardet = [ + {file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"}, + {file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"}, +] +click = [ + {file = "Click-7.0-py2.py3-none-any.whl", hash = "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13"}, + {file = "Click-7.0.tar.gz", hash = "sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7"}, +] +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.8-py2.py3-none-any.whl", hash = "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"}, + {file = "idna-2.8.tar.gz", hash = "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407"}, +] +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.7.0-py2.py3-none-any.whl", hash = "sha256:163b0632d4e31cef212976cf57b43d9fd6b0bac6e67c26015d611a647d5e7424"}, + {file = "pathspec-0.7.0.tar.gz", hash = "sha256:562aa70af2e0d434367d9790ad37aed893de47f1693e4201fd1d3dca15d19b96"}, +] +pyinstaller = [ + {file = "PyInstaller-3.6.tar.gz", hash = "sha256:3730fa80d088f8bb7084d32480eb87cbb4ddb64123363763cf8f2a1378c1c4b7"}, +] +pyobjc-core = [ + {file = "pyobjc-core-6.1.tar.gz", hash = "sha256:1a0fbf012fb575e0adf8c18cfd4453e657cc2c0deb2660c529bf524ba4c9149a"}, + {file = "pyobjc_core-6.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:470ccd754efb468a59426942673dfc3c5c59f33a5b8cae8a7fc1be975c2d4128"}, + {file = "pyobjc_core-6.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:751cdeb436cb181af2e2413015b072075590577c410c7f345080a38dd028b8ec"}, + {file = "pyobjc_core-6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8ccf44511cbe438fa6562c423c0c5f1dad7cfc0eadd6d8f112840f8845b44fda"}, +] +pyobjc-framework-cocoa = [ + {file = "pyobjc-framework-Cocoa-6.1.tar.gz", hash = "sha256:c4077d2e6f96e4f3fd9780d66778cf51d27f414822498b24410e9df7a6a4d531"}, + {file = "pyobjc_framework_Cocoa-6.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:32ba4d0ce811e2088bf0fc360c9545c06586934e895f7133655b8f2182e7019a"}, + {file = "pyobjc_framework_Cocoa-6.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:245e19156739f8068db474ad9561079cc698f08ef525e299b8eedc5531e02801"}, + {file = "pyobjc_framework_Cocoa-6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1dc428f867d35007ddf9de5b24eff5bfdf65c58b1d610abcb08bebd94c343312"}, +] +pyobjc-framework-coreservices = [ + {file = "pyobjc-framework-CoreServices-6.1.tar.gz", hash = "sha256:665f979403ebae16b4d9945d24829c12c2aeccc0338cd04a268a324b6cc654a2"}, + {file = "pyobjc_framework_CoreServices-6.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:0e28004a6fcc3d8928d7c8ddac2059651847851e2bad7fe2d1ed7fd12615065c"}, + {file = "pyobjc_framework_CoreServices-6.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a2977e948027677fca574a6c3fc4654f6644700bf9d2afa87c64afa2acf4b66e"}, + {file = "pyobjc_framework_CoreServices-6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:416c47d12640ddcdb773eee6a99e09d26326dadb15056d0f7734eff913d4ce7b"}, +] +pyobjc-framework-fsevents = [ + {file = "pyobjc-framework-FSEvents-6.1.tar.gz", hash = "sha256:7a635c86af744a1d17f0c6c3913bef87b5fd146e0311c03229eba9e512b81520"}, + {file = "pyobjc_framework_FSEvents-6.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:94c6953774b6d69e59d9781951f05ef57e352b3c530d4c236f463444852c3a88"}, + {file = "pyobjc_framework_FSEvents-6.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3a403ce5997cc01f23f1a70f8b4c919311b9a6b1fdd3c3d02d19079d711f954c"}, + {file = "pyobjc_framework_FSEvents-6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d2ae8748d1791dc9e3d19b41d3873283ac34ed17ff8fca70f1a199336a0477b5"}, +] +pyobjc-framework-launchservices = [ + {file = "pyobjc-framework-LaunchServices-6.1.tar.gz", hash = "sha256:1c1896f356e9c7ac6255863422565ed922589c10bba3dc2850729df666794346"}, + {file = "pyobjc_framework_LaunchServices-6.1-py2.py3-none-any.whl", hash = "sha256:944b8ce7fb4215019bb55bd48b46685032d8db3fc2ff8cd80dfe56356cd99fd2"}, +] +pyqt5 = [ + {file = "PyQt5-5.14.1-5.14.1-cp35.cp36.cp37.cp38-abi3-macosx_10_6_intel.whl", hash = "sha256:a0bfe9fd718bca4de3e33000347e048f73126b6dc46530eb020b0251a638ee9d"}, + {file = "PyQt5-5.14.1-5.14.1-cp35.cp36.cp37.cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:713b9a201f5e7b2fca8691373e5d5c8c2552a51d87ca9ffbb1461e34e3241211"}, + {file = "PyQt5-5.14.1-5.14.1-cp35.cp36.cp37.cp38-none-win32.whl", hash = "sha256:2d94ec761fb656707050c68b41958e3a9f755bb1df96c064470f4096d2899e32"}, + {file = "PyQt5-5.14.1-5.14.1-cp35.cp36.cp37.cp38-none-win_amd64.whl", hash = "sha256:31b142a868152d60c6323e0527edb692fdf05fd7cb4fe2fe9ce07d1ce560221a"}, + {file = "PyQt5-5.14.1.tar.gz", hash = "sha256:2f230f2dbd767099de7a0cb915abdf0cbc3256a0b5bb910eb09b99117db7a65b"}, +] +pyqt5-sip = [ + {file = "PyQt5_sip-12.7.1-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:f314f31f5fd39b06897f013f425137e511d45967150eb4e424a363d8138521c6"}, + {file = "PyQt5_sip-12.7.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b42021229424aa44e99b3b49520b799fd64ff6ae8b53f79f903bbd85719a28e4"}, + {file = "PyQt5_sip-12.7.1-cp35-cp35m-win32.whl", hash = "sha256:6b4860c4305980db509415d0af802f111d15f92016c9422eb753bc8883463456"}, + {file = "PyQt5_sip-12.7.1-cp35-cp35m-win_amd64.whl", hash = "sha256:d46b0f8effc554de52a1466b1bd80e5cb4bce635a75ac4e7ad6247c965dec5b9"}, + {file = "PyQt5_sip-12.7.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:3f665376d9e52faa9855c3736a66ce6d825f85c86d7774d3c393f09da23f4f86"}, + {file = "PyQt5_sip-12.7.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:1115728644bbadcde5fc8a16e7918bd31915a42dd6fb36b10d4afb78c582753e"}, + {file = "PyQt5_sip-12.7.1-cp36-cp36m-win32.whl", hash = "sha256:cbeeae6b45234a1654657f79943f8bccd3d14b4e7496746c62cf6fbce69442c7"}, + {file = "PyQt5_sip-12.7.1-cp36-cp36m-win_amd64.whl", hash = "sha256:8da842d3d7bf8931d1093105fb92702276b6dbb7e801abbaaa869405d616171a"}, + {file = "PyQt5_sip-12.7.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:1f4289276d355b6521dc2cc956189315da6f13adfb6bbab8f25ebd15e3bce1d4"}, + {file = "PyQt5_sip-12.7.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:c1e730a9eb2ec3869ed5d81b0f99f6e2460fb4d77750444c0ec183b771d798f7"}, + {file = "PyQt5_sip-12.7.1-cp37-cp37m-win32.whl", hash = "sha256:b5b4906445fe980aee76f20400116b6904bf5f30d0767489c13370e42a764020"}, + {file = "PyQt5_sip-12.7.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7ffa39763097f64de129cf5cc770a651c3f65d2466b4fe05bef2bd2efbaa38e6"}, + {file = "PyQt5_sip-12.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:288c6dc18a8d6a20981c07b715b5695d9b66880778565f3792bc6e38f14f20fb"}, + {file = "PyQt5_sip-12.7.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:ee1a12f09d5af2304273bfd2f6b43835c1467d5ed501a6c95f5405637fa7750a"}, + {file = "PyQt5_sip-12.7.1-cp38-cp38-win32.whl", hash = "sha256:8a18e6f45d482ddfe381789979d09ee13aa6450caa3a0476503891bccb3ac709"}, + {file = "PyQt5_sip-12.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:e28c3abc9b62a1b7e796891648b9f14f8167b31c8e7990fae79654777252bb4d"}, + {file = "PyQt5_sip-12.7.1.tar.gz", hash = "sha256:e6078f5ee7d31c102910d0c277a110e1c2a20a3fc88cd017a39e170120586d3f"}, +] +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"}, +] +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.1.8-cp27-cp27m-win32.whl", hash = "sha256:4e8f02d3d72ca94efc8396f8036c0d3bcc812aefc28ec70f35bb888c74a25161"}, + {file = "regex-2020.1.8-cp27-cp27m-win_amd64.whl", hash = "sha256:e6c02171d62ed6972ca8631f6f34fa3281d51db8b326ee397b9c83093a6b7242"}, + {file = "regex-2020.1.8-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:4eae742636aec40cf7ab98171ab9400393360b97e8f9da67b1867a9ee0889b26"}, + {file = "regex-2020.1.8-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:bd25bb7980917e4e70ccccd7e3b5740614f1c408a642c245019cff9d7d1b6149"}, + {file = "regex-2020.1.8-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:3e77409b678b21a056415da3a56abfd7c3ad03da71f3051bbcdb68cf44d3c34d"}, + {file = "regex-2020.1.8-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:07b39bf943d3d2fe63d46281d8504f8df0ff3fe4c57e13d1656737950e53e525"}, + {file = "regex-2020.1.8-cp36-cp36m-win32.whl", hash = "sha256:23e2c2c0ff50f44877f64780b815b8fd2e003cda9ce817a7fd00dea5600c84a0"}, + {file = "regex-2020.1.8-cp36-cp36m-win_amd64.whl", hash = "sha256:27429b8d74ba683484a06b260b7bb00f312e7c757792628ea251afdbf1434003"}, + {file = "regex-2020.1.8-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:0e182d2f097ea8549a249040922fa2b92ae28be4be4895933e369a525ba36576"}, + {file = "regex-2020.1.8-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e3cd21cc2840ca67de0bbe4071f79f031c81418deb544ceda93ad75ca1ee9f7b"}, + {file = "regex-2020.1.8-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:ecc6de77df3ef68fee966bb8cb4e067e84d4d1f397d0ef6fce46913663540d77"}, + {file = "regex-2020.1.8-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:26ff99c980f53b3191d8931b199b29d6787c059f2e029b2b0c694343b1708c35"}, + {file = "regex-2020.1.8-cp37-cp37m-win32.whl", hash = "sha256:7bcd322935377abcc79bfe5b63c44abd0b29387f267791d566bbb566edfdd146"}, + {file = "regex-2020.1.8-cp37-cp37m-win_amd64.whl", hash = "sha256:10671601ee06cf4dc1bc0b4805309040bb34c9af423c12c379c83d7895622bb5"}, + {file = "regex-2020.1.8-cp38-cp38-manylinux1_i686.whl", hash = "sha256:98b8ed7bb2155e2cbb8b76f627b2fd12cf4b22ab6e14873e8641f266e0fb6d8f"}, + {file = "regex-2020.1.8-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6a6ba91b94427cd49cd27764679024b14a96874e0dc638ae6bdd4b1a3ce97be1"}, + {file = "regex-2020.1.8-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:6a6ae17bf8f2d82d1e8858a47757ce389b880083c4ff2498dba17c56e6c103b9"}, + {file = "regex-2020.1.8-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:0932941cdfb3afcbc26cc3bcf7c3f3d73d5a9b9c56955d432dbf8bbc147d4c5b"}, + {file = "regex-2020.1.8-cp38-cp38-win32.whl", hash = "sha256:d58e4606da2a41659c84baeb3cfa2e4c87a74cec89a1e7c56bee4b956f9d7461"}, + {file = "regex-2020.1.8-cp38-cp38-win_amd64.whl", hash = "sha256:e7c7661f7276507bce416eaae22040fd91ca471b5b33c13f8ff21137ed6f248c"}, + {file = "regex-2020.1.8.tar.gz", hash = "sha256:d0f424328f9822b0323b3b6f2e4b9c90960b24743d220763c7f07071e0778351"}, +] +requests = [ + {file = "requests-2.22.0-py2.py3-none-any.whl", hash = "sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31"}, + {file = "requests-2.22.0.tar.gz", hash = "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4"}, +] +toml = [ + {file = "toml-0.10.0-py2.7.egg", hash = "sha256:f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3"}, + {file = "toml-0.10.0-py2.py3-none-any.whl", hash = "sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e"}, + {file = "toml-0.10.0.tar.gz", hash = "sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c"}, +] +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.8-py2.py3-none-any.whl", hash = "sha256:2f3db8b19923a873b3e5256dc9c2dedfa883e33d87c690d9c7913e1f40673cdc"}, + {file = "urllib3-1.25.8.tar.gz", hash = "sha256:87716c2d2a7121198ebcb7ce7cccf6ce5e9ba539041cfbaeecfb641dc0bf6acc"}, +] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..b94e5a0 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,27 @@ +[tool.poetry] +name = "dangerzone" +version = "0.1.0" +description = "Take potentially dangerous PDFs, office documents, or images and convert them to a safe PDF" +authors = ["Micah Lee "] +license = "MIT" + +[tool.poetry.dependencies] +python = "^3.7" +PyQt5 = "^5.14.1" +click = "^7.0" +appdirs = "^1.4.3" +requests = "^2.22.0" +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 = "win32"} + +[tool.poetry.dev-dependencies] +black = "^19.10b0" +pyinstaller = {version = "^3.6", platform = "darwin"} +setuptools = {version = "^45.2.0", platform = "win32"} + +[build-system] +requires = ["poetry>=0.12"] +build-backend = "poetry.masonry.api" From 791d930a554b189eca194eb1a0be88e0baf38995 Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Thu, 13 Feb 2020 15:33:08 -0800 Subject: [PATCH 04/10] In Windows, add startupinfo to subprocess calls to prevent terminal windows from opening in the background --- dangerzone/common.py | 8 ++++++++ dangerzone/docker_installer.py | 15 ++++++++++++--- dangerzone/tasks.py | 1 + 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/dangerzone/common.py b/dangerzone/common.py index 95dc508..34327a8 100644 --- a/dangerzone/common.py +++ b/dangerzone/common.py @@ -341,3 +341,11 @@ class Common(object): pass return pdf_viewers + + def get_subprocess_startupinfo(self): + if platform.system() == "Windows": + startupinfo = subprocess.STARTUPINFO() + startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW + return startupinfo + else: + return None diff --git a/dangerzone/docker_installer.py b/dangerzone/docker_installer.py index 82db353..2f0efeb 100644 --- a/dangerzone/docker_installer.py +++ b/dangerzone/docker_installer.py @@ -28,7 +28,11 @@ def is_docker_installed(common): def is_docker_ready(common): # Run `docker ps` without an error try: - subprocess.run([common.container_runtime, "ps"], check=True) + subprocess.run( + [common.container_runtime, "ps"], + check=True, + startupinfo=common.get_subprocess_startupinfo(), + ) return True except subprocess.CalledProcessError: return False @@ -36,7 +40,9 @@ def is_docker_ready(common): def launch_docker_windows(): docker_desktop_path = "C:\\Program Files\\Docker\\Docker\\Docker Desktop.exe" - subprocess.Popen([docker_desktop_path]) + subprocess.Popen( + [docker_desktop_path], startupinfo=common.get_subprocess_startupinfo() + ) class DockerInstaller(QtWidgets.QDialog): @@ -278,7 +284,10 @@ class Installer(QtCore.QThread): elif platform.system() == "Windows": try: # Run the installer - subprocess.run([self.installer_filename]) + subprocess.run( + [self.installer_filename], + startupinfo=common.get_subprocess_startupinfo(), + ) self.install_finished.emit() except Exception as e: diff --git a/dangerzone/tasks.py b/dangerzone/tasks.py index 1b6f720..eb6f38c 100644 --- a/dangerzone/tasks.py +++ b/dangerzone/tasks.py @@ -31,6 +31,7 @@ class TaskBase(QtCore.QThread): stderr=subprocess.PIPE, bufsize=1, universal_newlines=True, + startupinfo=self.common.get_subprocess_startupinfo(), ) as p: if watch == "stdout": pipe = p.stdout From e3069e9e05d7545444ef299b44e9d681e38296fa Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Thu, 13 Feb 2020 15:55:28 -0800 Subject: [PATCH 05/10] Fail early if container pull or build fail --- dangerzone/tasks.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/dangerzone/tasks.py b/dangerzone/tasks.py index eb6f38c..c246f39 100644 --- a/dangerzone/tasks.py +++ b/dangerzone/tasks.py @@ -61,7 +61,12 @@ class PullImageTask(TaskBase): self.update_label.emit("Pulling container image") self.update_details.emit("") args = ["pull", "ubuntu:20.04"] - self.exec_container(args, watch="stderr") + returncode, _ = self.exec_container(args, watch="stderr") + + if returncode != 0: + self.task_failed.emit(f"Return code: {returncode}") + return + self.task_finished.emit() @@ -75,7 +80,12 @@ class BuildContainerTask(TaskBase): self.update_label.emit("Building container") self.update_details.emit("") args = ["build", "-t", "dangerzone", container_path] - self.exec_container(args) + returncode, _ = self.exec_container(args) + + if returncode != 0: + self.task_failed.emit(f"Return code: {returncode}") + return + self.task_finished.emit() From 7a22b9815689dd167f1aa0247ccef1fb57560987 Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Thu, 13 Feb 2020 16:12:18 -0800 Subject: [PATCH 06/10] Add notice about building container maybe taking a long time --- dangerzone/tasks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dangerzone/tasks.py b/dangerzone/tasks.py index c246f39..11a093b 100644 --- a/dangerzone/tasks.py +++ b/dangerzone/tasks.py @@ -77,7 +77,7 @@ class BuildContainerTask(TaskBase): def run(self): container_path = self.common.get_resource_path("container") - self.update_label.emit("Building container") + self.update_label.emit("Building container (this might take a long time)") self.update_details.emit("") args = ["build", "-t", "dangerzone", container_path] returncode, _ = self.exec_container(args) From 93fc079c17c5186ee58dcb2eb5a5ad3f1e508009 Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Wed, 19 Feb 2020 14:27:47 -0800 Subject: [PATCH 07/10] Add wmi dependency for windows --- poetry.lock | 15 ++++++++++++++- pyproject.toml | 1 + 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index 843ce48..cc66fb1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -274,8 +274,17 @@ brotli = ["brotlipy (>=0.6.0)"] secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"] +[[package]] +category = "main" +description = "Windows Management Instrumentation" +marker = "sys_platform == \"windows\"" +name = "wmi" +optional = false +python-versions = "*" +version = "1.4.9" + [metadata] -content-hash = "1a7f436898ad10813c8bd4f2a4e12064e2777265bbd91616b00a997638a68e16" +content-hash = "28c51f60ace8c8578c21279f8c46ba095d0ec1f1f86bb155c24cba67ac3291ee" python-versions = "^3.7" [metadata.files] @@ -458,3 +467,7 @@ urllib3 = [ {file = "urllib3-1.25.8-py2.py3-none-any.whl", hash = "sha256:2f3db8b19923a873b3e5256dc9c2dedfa883e33d87c690d9c7913e1f40673cdc"}, {file = "urllib3-1.25.8.tar.gz", hash = "sha256:87716c2d2a7121198ebcb7ce7cccf6ce5e9ba539041cfbaeecfb641dc0bf6acc"}, ] +wmi = [ + {file = "WMI-1.4.9.win32.exe", hash = "sha256:b1c57a5c7e27596736026ec7dd9a7c5318dad8248e7638f40c60c33cb33ac935"}, + {file = "WMI-1.4.9.zip", hash = "sha256:192ccfad3d7bb3ef43116d753f4d5cf85c0a6b738f832cc131e928fd93cdd400"}, +] diff --git a/pyproject.toml b/pyproject.toml index b94e5a0..90b91e2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,6 +16,7 @@ pyobjc-core = {version = "^6.1", platform = "darwin"} pyobjc-framework-launchservices = {version = "^6.1", platform = "darwin"} macholib = "^1.14" pywin32 = {version = "^227", platform = "win32"} +wmi = {version = "^1.4.9", platform = "windows"} [tool.poetry.dev-dependencies] black = "^19.10b0" From 960956bc95391e1939fc283ddd007931d1c3514f Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Wed, 19 Feb 2020 14:54:42 -0800 Subject: [PATCH 08/10] Fix windows build instructions --- BUILD.md | 1 + 1 file changed, 1 insertion(+) diff --git a/BUILD.md b/BUILD.md index 8489947..a042f27 100644 --- a/BUILD.md +++ b/BUILD.md @@ -143,6 +143,7 @@ Then, compile the bootloader: ``` cd bootloader python waf distclean all --target-arch=32bit --msvc_targets=x86 +cd .. ``` Finally, install the PyInstaller module into your poetry environment: From 81627379f693c3902a24e1ab1c6cf7e94e37b305 Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Thu, 20 Feb 2020 09:38:49 -0800 Subject: [PATCH 09/10] Pass common into Installer, so Docker Desktop for Windows installer will run --- dangerzone/docker_installer.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dangerzone/docker_installer.py b/dangerzone/docker_installer.py index 2f0efeb..f4d5343 100644 --- a/dangerzone/docker_installer.py +++ b/dangerzone/docker_installer.py @@ -175,7 +175,7 @@ class DockerInstaller(QtWidgets.QDialog): self.timer.start(10) def start_installer(self): - self.install_t = Installer(self.installer_filename) + self.install_t = Installer(self.common, self.installer_filename) self.install_t.install_finished.connect(self.install_finished) self.install_t.install_failed.connect(self.install_failed) self.install_t.update_task_label.connect(self.update_task_label) @@ -243,8 +243,9 @@ class Installer(QtCore.QThread): install_failed = QtCore.pyqtSignal(str) update_task_label = QtCore.pyqtSignal(str) - def __init__(self, installer_filename): + def __init__(self, common, installer_filename): super(Installer, self).__init__() + self.common = common self.installer_filename = installer_filename def run(self): @@ -286,7 +287,7 @@ class Installer(QtCore.QThread): # Run the installer subprocess.run( [self.installer_filename], - startupinfo=common.get_subprocess_startupinfo(), + startupinfo=self.common.get_subprocess_startupinfo(), ) self.install_finished.emit() From 65121ed72953d5a71ffd058b5cd76937e600ff8e Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Thu, 20 Feb 2020 09:46:34 -0800 Subject: [PATCH 10/10] Also pass common into launch_docker_windows function --- dangerzone/__init__.py | 2 +- dangerzone/docker_installer.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dangerzone/__init__.py b/dangerzone/__init__.py index 83b4e95..4c4c5e1 100644 --- a/dangerzone/__init__.py +++ b/dangerzone/__init__.py @@ -64,7 +64,7 @@ def main(filename): if not is_docker_ready(common): print("Docker is not running") - launch_docker_windows() + launch_docker_windows(common) # Wait up to 20 minutes for docker to be ready for i in range(120): diff --git a/dangerzone/docker_installer.py b/dangerzone/docker_installer.py index f4d5343..d546546 100644 --- a/dangerzone/docker_installer.py +++ b/dangerzone/docker_installer.py @@ -38,7 +38,7 @@ def is_docker_ready(common): return False -def launch_docker_windows(): +def launch_docker_windows(common): docker_desktop_path = "C:\\Program Files\\Docker\\Docker\\Docker Desktop.exe" subprocess.Popen( [docker_desktop_path], startupinfo=common.get_subprocess_startupinfo()