From ba68764fcb61d2baba9740baa5a88b09a24f23ac Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Fri, 30 Dec 2022 15:30:53 +1000 Subject: [PATCH] Another attempt at fixing missing cacert.pem A few reports like https://forums.ankiweb.net/t/error-report-check-database-did-not-work/25796 indicate that the previous solution has not helped, and has just made things worse. My guess is that AppNap on macOS is preventing the timer from even running before the file gets cleaned up. --- qt/aqt/main.py | 16 ---------------- qt/aqt/package.py | 20 ++++++++++++++++++++ qt/bundle/mac/src/main.rs | 2 +- qt/bundle/pyoxidizer.bzl | 2 ++ 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/qt/aqt/main.py b/qt/aqt/main.py index e0a7a688c..296e8264c 100644 --- a/qt/aqt/main.py +++ b/qt/aqt/main.py @@ -1382,13 +1382,6 @@ title="{}" {}>{}""".format( True, parent=self, ) - self.progress.timer( - 12 * 60 * 1000, - self.refresh_certs, - repeat=True, - requiresCollection=False, - parent=self, - ) def onRefreshTimer(self) -> None: if self.state == "deckBrowser": @@ -1404,15 +1397,6 @@ title="{}" {}>{}""".format( if elap > minutes * 60: self.maybe_auto_sync_media() - def refresh_certs(self) -> None: - # The requests library copies the certs into a temporary folder on startup, - # and chokes when the file is later missing due to temp file cleaners. - # Work around the issue by accessing them once every 12 hours. - from requests.certs import where # type: ignore[attr-defined] - - with open(where(), "rb") as f: - f.read() - # Backups ########################################################################## diff --git a/qt/aqt/package.py b/qt/aqt/package.py index 1cee7d5b4..6bece47d1 100644 --- a/qt/aqt/package.py +++ b/qt/aqt/package.py @@ -7,6 +7,7 @@ from __future__ import annotations import os import sys +from pathlib import Path def _fix_pywin32() -> None: @@ -49,6 +50,24 @@ def _patch_pkgutil() -> None: pkgutil.get_data = get_data_custom +def _patch_certifi() -> None: + """Tell certifi (and thus requests) to use a file in our package folder. + + By default it creates a copy of the data in a temporary folder, which then gets + cleaned up by macOS's temp file cleaner.""" + import certifi + + def where() -> str: + prefix = Path(sys.prefix) + if sys.platform == "darwin": + path = prefix / "../Resources/certifi/cacert.pem" + else: + path = prefix / "lib" / "certifi" / "cacert.pem" + return str(path) + + certifi.where = where + + def packaged_build_setup() -> None: if not getattr(sys, "frozen", False): return @@ -59,6 +78,7 @@ def packaged_build_setup() -> None: _fix_pywin32() _patch_pkgutil() + _patch_certifi() # escape hatch for debugging issues with packaged build startup if os.getenv("ANKI_STARTUP_REPL"): diff --git a/qt/bundle/mac/src/main.rs b/qt/bundle/mac/src/main.rs index 399249b3d..597f10157 100644 --- a/qt/bundle/mac/src/main.rs +++ b/qt/bundle/mac/src/main.rs @@ -132,7 +132,7 @@ fn make_app(kind: DistKind, mut plist: plist::Dictionary, stamp: &Utf8Path) -> R let path_str = relative_path.to_str().unwrap(); if path_str.contains("libankihelper") { builder.add_file_macos("libankihelper.dylib", entry)?; - } else if path_str.contains("aqt/data") { + } else if path_str.contains("aqt/data") || path_str.contains("certifi") { builder.add_file_resources(relative_path.strip_prefix("lib").unwrap(), entry)?; } else { if path_str.contains("__pycache__") { diff --git a/qt/bundle/pyoxidizer.bzl b/qt/bundle/pyoxidizer.bzl index 0fba834b1..57721ef77 100644 --- a/qt/bundle/pyoxidizer.bzl +++ b/qt/bundle/pyoxidizer.bzl @@ -55,6 +55,8 @@ def handle_resource(policy, resource): for prefix in included_resource_packages: if resource.package.startswith(prefix): resource.add_include = True + if resource.package == "certifi": + resource.add_location = "filesystem-relative:lib" for suffix in excluded_resource_suffixes: if resource.name.endswith(suffix): resource.add_include = False