updated package scripts

This commit is contained in:
Damien Elmes 2021-10-28 18:46:45 +10:00
parent b5e9eba26f
commit 5a8e064a7d
34 changed files with 1482 additions and 60 deletions

View file

@ -6,6 +6,7 @@ license = "AGPL-3.0-or-later"
[workspace] [workspace]
members = ["rslib", "rslib/i18n", "pylib/rsbridge"] members = ["rslib", "rslib/i18n", "pylib/rsbridge"]
exclude = ["qt/package"]
[lib] [lib]
# dummy top level for tooling # dummy top level for tooling

View file

@ -31,7 +31,7 @@ from anki.sync_pb2 import SyncServerMethodRequest
Method = SyncServerMethodRequest.Method # pylint: disable=no-member Method = SyncServerMethodRequest.Method # pylint: disable=no-member
app = flask.Flask(__name__) app = flask.Flask(__name__, root_path="/fake")
col: Collection col: Collection
trace = os.getenv("TRACE") trace = os.getenv("TRACE")

View file

@ -3,13 +3,27 @@
from __future__ import annotations from __future__ import annotations
import sys
if sys.version_info[0] < 3 or sys.version_info[1] < 9:
raise Exception("Anki requires Python 3.9+")
# ensure unicode filenames are supported
try:
"テスト".encode(sys.getfilesystemencoding())
except UnicodeEncodeError as exc:
raise Exception("Anki requires a UTF-8 locale.") from exc
from .package import packaged_build_setup
packaged_build_setup()
import argparse import argparse
import builtins import builtins
import cProfile import cProfile
import getpass import getpass
import locale import locale
import os import os
import sys
import tempfile import tempfile
import traceback import traceback
from typing import Any, Callable, Optional, cast from typing import Any, Callable, Optional, cast
@ -24,15 +38,6 @@ from aqt import gui_hooks
from aqt.qt import * from aqt.qt import *
from aqt.utils import TR, tr from aqt.utils import TR, tr
if sys.version_info[0] < 3 or sys.version_info[1] < 9:
raise Exception("Anki requires Python 3.9+")
# ensure unicode filenames are supported
try:
"テスト".encode(sys.getfilesystemencoding())
except UnicodeEncodeError as exc:
raise Exception("Anki requires a UTF-8 locale.") from exc
# compat aliases # compat aliases
anki.version = _version # type: ignore anki.version = _version # type: ignore
anki.Collection = Collection # type: ignore anki.Collection = Collection # type: ignore
@ -233,12 +238,8 @@ def setupLangAndBackend(
# load qt translations # load qt translations
_qtrans = QTranslator() _qtrans = QTranslator()
from aqt.utils import aqt_data_folder
if isMac and getattr(sys, "frozen", False): if isMac and getattr(sys, "frozen", False):
qt_dir = os.path.abspath( qt_dir = os.path.join(sys.prefix, "../Resources/qt_translations")
os.path.join(aqt_data_folder(), "..", "qt_translations")
)
else: else:
if qtmajor == 5: if qtmajor == 5:
qt_dir = QLibraryInfo.location(QLibraryInfo.TranslationsPath) # type: ignore qt_dir = QLibraryInfo.location(QLibraryInfo.TranslationsPath) # type: ignore
@ -429,6 +430,7 @@ def write_profile_results() -> None:
def run() -> None: def run() -> None:
print("Preparing to run...")
try: try:
_run() _run()
except Exception as e: except Exception as e:
@ -617,6 +619,7 @@ def _run(argv: Optional[list[str]] = None, exec: bool = True) -> Optional[AnkiAp
mw = aqt.main.AnkiQt(app, pm, backend, opts, args) mw = aqt.main.AnkiQt(app, pm, backend, opts, args)
if exec: if exec:
print("Starting main loop...")
app.exec() app.exec()
else: else:
return app return app

View file

@ -199,7 +199,7 @@ def _builtin_data(path: str) -> bytes:
with open(full_path, "rb") as f: with open(full_path, "rb") as f:
return f.read() return f.read()
else: else:
if isWin and not getattr(sys, "frozen", False) : if isWin and not getattr(sys, "frozen", False):
# default Python resource loader expects backslashes on Windows # default Python resource loader expects backslashes on Windows
path = path.replace("/", "\\") path = path.replace("/", "\\")
reader = aqt.__loader__.get_resource_reader("aqt") # type: ignore reader = aqt.__loader__.get_resource_reader("aqt") # type: ignore

68
qt/aqt/package.py Normal file
View file

@ -0,0 +1,68 @@
# Copyright: Ankitects Pty Ltd and contributors
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
"""Helpers for the packaged version of Anki."""
from __future__ import annotations
import os
import sys
def _fix_pywin32() -> None:
# extend sys.path with .pth files
import site
site.addsitedir(sys.path[0])
# use updated sys.path to locate dll folder and add it to path
path = sys.path[-1]
path = path.replace("Pythonwin", "pywin32_system32")
os.environ["PATH"] += ";" + path
# import Python modules from .dll files
import importlib.machinery
for name in "pythoncom", "pywintypes":
filename = os.path.join(path, name + "39.dll")
loader = importlib.machinery.ExtensionFileLoader(name, filename)
spec = importlib.machinery.ModuleSpec(name=name, loader=loader, origin=filename)
_mod = importlib._bootstrap._load(spec) # type: ignore
def _patch_pkgutil() -> None:
"""Teach pkgutil.get_data() how to read files from in-memory resources.
This is required for jsonschema."""
import importlib
import pkgutil
def get_data_custom(package: str, resource: str) -> bytes | None:
try:
module = importlib.import_module(package)
reader = module.__loader__.get_resource_reader(package) # type: ignore[attr-defined]
with reader.open_resource(resource) as f:
return f.read()
except:
return None
pkgutil.get_data = get_data_custom
def packaged_build_setup() -> None:
if not getattr(sys, "frozen", False):
return
print("Initial setup...")
if sys.platform == "win32":
_fix_pywin32()
_patch_pkgutil()
# escape hatch for debugging issues with packaged build startup
if os.getenv("ANKI_STARTUP_REPL") and os.isatty(sys.stdin.fileno()):
import code
code.InteractiveConsole().interact()
sys.exit(0)

View file

@ -4,6 +4,7 @@
"""Platform-specific functionality.""" """Platform-specific functionality."""
import os import os
import sys
from ctypes import CDLL from ctypes import CDLL
import aqt.utils import aqt.utils
@ -24,5 +25,8 @@ def set_dark_mode(enabled: bool) -> bool:
def _set_dark_mode(enabled: bool) -> None: def _set_dark_mode(enabled: bool) -> None:
path = os.path.join(aqt.utils.aqt_data_folder(), "lib", "libankihelper.dylib") if getattr(sys, "frozen", False):
path = os.path.join(sys.prefix, "libankihelper.dylib")
else:
path = os.path.join(aqt.utils.aqt_data_folder(), "lib", "libankihelper.dylib")
CDLL(path).set_darkmode_enabled(enabled) CDLL(path).set_darkmode_enabled(enabled)

View file

@ -14,6 +14,7 @@ import wave
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from concurrent.futures import Future from concurrent.futures import Future
from operator import itemgetter from operator import itemgetter
from pathlib import Path
from typing import Any, Callable, cast from typing import Any, Callable, cast
from markdown import markdown from markdown import markdown
@ -234,16 +235,15 @@ def _packagedCmd(cmd: list[str]) -> tuple[Any, dict[str, str]]:
if "LD_LIBRARY_PATH" in env: if "LD_LIBRARY_PATH" in env:
del env["LD_LIBRARY_PATH"] del env["LD_LIBRARY_PATH"]
if isMac: if isMac:
dir = os.path.dirname(os.path.abspath(__file__)) path = Path(sys.prefix).joinpath("audio").joinpath(cmd[0])
exeDir = os.path.abspath(f"{dir}/../../Resources/audio") if path.exists():
else: cmd[0] = str(path)
exeDir = os.path.dirname(os.path.abspath(sys.argv[0])) return cmd, env
if isWin and not cmd[0].endswith(".exe"): adjusted_path = os.path.join(sys.prefix, cmd[0])
cmd[0] += ".exe" if isWin and not adjusted_path.endswith(".exe"):
path = os.path.join(exeDir, cmd[0]) adjusted_path += ".exe"
if not os.path.exists(path): if os.path.exists(adjusted_path):
return cmd, env cmd[0] = adjusted_path
cmd[0] = path
return cmd, env return cmd, env

View file

@ -30,21 +30,19 @@ def aqt_data_folder() -> str:
# running in Bazel on macOS? # running in Bazel on macOS?
if path := os.getenv("AQT_DATA_FOLDER"): if path := os.getenv("AQT_DATA_FOLDER"):
return path return path
# running in place? # packaged?
dir = os.path.join(os.path.dirname(__file__), "data") elif getattr(sys, "frozen", False):
if os.path.exists(dir): path = os.path.join(sys.prefix, "lib/aqt/data")
return dir if os.path.exists(path):
# packaged install? return path
if isMac: else:
dir2 = os.path.join(sys.prefix, "..", "Resources", "aqt_data") return os.path.join(sys.prefix, "../Resources/aqt/data")
elif os.path.exists(dir := os.path.join(os.path.dirname(__file__), "data")):
return os.path.abspath(dir)
else: else:
dir2 = os.path.join(sys.prefix, "aqt_data") # should only happen when running unit tests
if os.path.exists(dir2): print("warning, data folder not found")
return dir2 return "."
# should only happen when running unit tests
print("warning, data folder not found")
return "."
# shortcut to access Fluent translations; set as # shortcut to access Fluent translations; set as

View file

@ -33,7 +33,7 @@ def fix_pywin32_in_bazel(force=False):
import importlib.machinery import importlib.machinery
name = "pythoncom" name = "pythoncom"
filename = os.path.join(path, "pythoncom38.dll") filename = os.path.join(path, "pythoncom39.dll")
loader = importlib.machinery.ExtensionFileLoader(name, filename) loader = importlib.machinery.ExtensionFileLoader(name, filename)
spec = importlib.machinery.ModuleSpec(name=name, loader=loader, origin=filename) spec = importlib.machinery.ModuleSpec(name=name, loader=loader, origin=filename)
_mod = importlib._bootstrap._load(spec) _mod = importlib._bootstrap._load(spec)

42
qt/package/.cargo/config Normal file
View file

@ -0,0 +1,42 @@
# By default Rust will not export dynamic symbols from built executables.
# Python symbols need to be exported from executables in order for that
# executable to load Python extension modules, which are shared libraries.
# Otherwise, the extension module / shared library is unable to resolve
# Python symbols. This file contains target-specific configuration
# overrides to export dynamic symbols from executables.
#
# Ideally we would achieve this functionality via the build.rs build
# script. But custom compiler flags via build scripts apparently only
# support limited options.
[target.i686-unknown-linux-gnu]
rustflags = ["-C", "link-args=-Wl,-export-dynamic"]
[target.x86_64-unknown-linux-gnu]
rustflags = ["-C", "link-args=-Wl,-export-dynamic"]
[target.aarch64-apple-darwin]
rustflags = ["-C", "link-args=-rdynamic"]
[target.x86_64-apple-darwin]
rustflags = ["-C", "link-args=-rdynamic"]
# The Windows standalone_static distributions use the static CRT (/MT compiler
# flag). By default, Rust will build with the dynamically linked / DLL CRT
# (/MD compiler flag). `pyoxidizer build` should adjust RUSTFLAGS automatically
# when a standalone_static distribution is being used. But if invoking `cargo`
# directly, you'll need to override the default CRT linkage by either passing
# RUSTFLAGS="-C target-feature=+crt-static" or by commenting out the lines
# below. Note that use of `target-feature=+crt-static` will prevent
# standalone_dynamic distributions from working.
#
# The standalone_static distributions also have duplicate symbols and some
# build configurations will result in hard linker errors because of this. We
# also add the /FORCE:MULTIPLE linker argument to prevent this from being a
# fatal error.
#[target.i686-pc-windows-msvc]
#rustflags = ["-C", "target-feature=+crt-static", "-C", "link-args=/FORCE:MULTIPLE"]
#
#[target.x86_64-pc-windows-msvc]
#rustflags = ["-C", "target-feature=+crt-static", "-C", "link-args=/FORCE:MULTIPLE"]

644
qt/package/Cargo.lock generated Normal file
View file

@ -0,0 +1,644 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
"memchr",
]
[[package]]
name = "anki"
version = "0.1.0"
dependencies = [
"embed-resource",
"jemallocator",
"mimalloc",
"pyembed",
"snmalloc-rs",
]
[[package]]
name = "anyhow"
version = "1.0.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1"
[[package]]
name = "base64"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
dependencies = [
"byteorder",
]
[[package]]
name = "base64"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cc"
version = "1.0.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "charset"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f426e64df1c3de26cbf44593c6ffff5dbfd43bbf9de0d075058558126b3fc73"
dependencies = [
"base64 0.10.1",
"encoding_rs",
]
[[package]]
name = "cmake"
version = "0.1.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7b858541263efe664aead4a5209a4ae5c5d2811167d4ed4ee0944503f8d2089"
dependencies = [
"cc",
]
[[package]]
name = "cty"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35"
[[package]]
name = "dunce"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "453440c271cf5577fd2a40e4942540cb7d0d2f85e27c8d07dd0023c925a67541"
[[package]]
name = "either"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "embed-resource"
version = "1.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85505eb239fc952b300f29f0556d2d884082a83566768d980278d8faf38c780d"
dependencies = [
"cc",
"vswhom",
"winreg",
]
[[package]]
name = "encoding_rs"
version = "0.8.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a74ea89a0a1b98f6332de42c95baff457ada66d1cb4030f9ff151b2041a1c746"
dependencies = [
"cfg-if",
]
[[package]]
name = "fs_extra"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394"
[[package]]
name = "indoc"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47741a8bc60fb26eb8d6e0238bbb26d8575ff623fdc97b1a2c00c050b9684ed8"
dependencies = [
"indoc-impl",
"proc-macro-hack",
]
[[package]]
name = "indoc-impl"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce046d161f000fffde5f432a0d034d0341dc152643b2598ed5bfce44c4f3a8f0"
dependencies = [
"proc-macro-hack",
"proc-macro2",
"quote",
"syn",
"unindent",
]
[[package]]
name = "instant"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [
"cfg-if",
]
[[package]]
name = "itertools"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf"
dependencies = [
"either",
]
[[package]]
name = "jemalloc-sys"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d3b9f3f5c9b31aa0f5ed3260385ac205db665baa41d49bb8338008ae94ede45"
dependencies = [
"cc",
"fs_extra",
"libc",
]
[[package]]
name = "jemallocator"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43ae63fcfc45e99ab3d1b29a46782ad679e98436c3169d15a167a1108a724b69"
dependencies = [
"jemalloc-sys",
"libc",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "869d572136620d55835903746bcb5cdc54cb2851fd0aeec53220b4bb65ef3013"
[[package]]
name = "libmimalloc-sys"
version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d1b8479c593dba88c2741fc50b92e13dbabbbe0bd504d979f244ccc1a5b1c01"
dependencies = [
"cc",
"cty",
]
[[package]]
name = "lock_api"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109"
dependencies = [
"scopeguard",
]
[[package]]
name = "mailparse"
version = "0.13.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ee6e1ca1c8396da58f8128176f6980dd57bec84c8670a479519d3655f2d6734"
dependencies = [
"base64 0.13.0",
"charset",
"quoted_printable",
]
[[package]]
name = "memchr"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "memmap"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "memory-module-sys"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3bbdce2925c681860b08875119254fb5543dbf6337c56ff93afebeed9c686da3"
dependencies = [
"cc",
"libc",
"winapi",
]
[[package]]
name = "mimalloc"
version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb74897ce508e6c49156fd1476fc5922cbc6e75183c65e399c765a09122e5130"
dependencies = [
"libmimalloc-sys",
]
[[package]]
name = "once_cell"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
[[package]]
name = "parking_lot"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
dependencies = [
"instant",
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
dependencies = [
"cfg-if",
"instant",
"libc",
"redox_syscall",
"smallvec",
"winapi",
]
[[package]]
name = "paste"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45ca20c77d80be666aef2b45486da86238fabe33e38306bd3118fe4af33fa880"
dependencies = [
"paste-impl",
"proc-macro-hack",
]
[[package]]
name = "paste-impl"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d95a7db200b97ef370c8e6de0088252f7e0dfff7d047a28528e47456c0fc98b6"
dependencies = [
"proc-macro-hack",
]
[[package]]
name = "proc-macro-hack"
version = "0.5.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
[[package]]
name = "proc-macro2"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edc3358ebc67bc8b7fa0c007f945b0b18226f78437d61bec735a9eb96b61ee70"
dependencies = [
"unicode-xid",
]
[[package]]
name = "pyembed"
version = "0.18.0-pre"
source = "git+https://github.com/ankitects/PyOxidizer.git?rev=ffbfe66912335bc816074c7a08aed06e26bfca7f#ffbfe66912335bc816074c7a08aed06e26bfca7f"
dependencies = [
"anyhow",
"dunce",
"jemalloc-sys",
"libmimalloc-sys",
"once_cell",
"pyo3",
"pyo3-build-config",
"python-oxidized-importer",
"python-packaging",
"snmalloc-sys",
]
[[package]]
name = "pyo3"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35100f9347670a566a67aa623369293703322bb9db77d99d7df7313b575ae0c8"
dependencies = [
"cfg-if",
"indoc",
"libc",
"parking_lot",
"paste",
"pyo3-build-config",
"pyo3-macros",
"unindent",
]
[[package]]
name = "pyo3-build-config"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d12961738cacbd7f91b7c43bc25cfeeaa2698ad07a04b3be0aa88b950865738f"
dependencies = [
"once_cell",
]
[[package]]
name = "pyo3-macros"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc0bc5215d704824dfddddc03f93cb572e1155c68b6761c37005e1c288808ea8"
dependencies = [
"pyo3-macros-backend",
"quote",
"syn",
]
[[package]]
name = "pyo3-macros-backend"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71623fc593224afaab918aa3afcaf86ed2f43d34f6afde7f3922608f253240df"
dependencies = [
"proc-macro2",
"pyo3-build-config",
"quote",
"syn",
]
[[package]]
name = "python-oxidized-importer"
version = "0.3.0-pre"
source = "git+https://github.com/ankitects/PyOxidizer.git?rev=ffbfe66912335bc816074c7a08aed06e26bfca7f#ffbfe66912335bc816074c7a08aed06e26bfca7f"
dependencies = [
"anyhow",
"lazy_static",
"memmap",
"memory-module-sys",
"once_cell",
"pyo3",
"python-packaging",
"python-packed-resources",
"tugger-file-manifest",
"winapi",
]
[[package]]
name = "python-packaging"
version = "0.11.0-pre"
source = "git+https://github.com/ankitects/PyOxidizer.git?rev=ffbfe66912335bc816074c7a08aed06e26bfca7f#ffbfe66912335bc816074c7a08aed06e26bfca7f"
dependencies = [
"anyhow",
"byteorder",
"encoding_rs",
"itertools",
"mailparse",
"once_cell",
"python-packed-resources",
"regex",
"spdx",
"tugger-file-manifest",
"tugger-licensing",
"walkdir",
]
[[package]]
name = "python-packed-resources"
version = "0.8.0-pre"
source = "git+https://github.com/ankitects/PyOxidizer.git?rev=ffbfe66912335bc816074c7a08aed06e26bfca7f#ffbfe66912335bc816074c7a08aed06e26bfca7f"
dependencies = [
"anyhow",
"byteorder",
]
[[package]]
name = "quote"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
dependencies = [
"proc-macro2",
]
[[package]]
name = "quoted_printable"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1238256b09923649ec89b08104c4dfe9f6cb2fea734a5db5384e44916d59e9c5"
[[package]]
name = "redox_syscall"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
dependencies = [
"bitflags",
]
[[package]]
name = "regex"
version = "1.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "smallvec"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
[[package]]
name = "snmalloc-rs"
version = "0.2.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36acaace2719c972eab3ef6a6b3aee4495f0bf300f59715bb9cff6c5acf4ae20"
dependencies = [
"snmalloc-sys",
]
[[package]]
name = "snmalloc-sys"
version = "0.2.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35a7e6e7d5fe756bee058ddedefc7e0a9f9c8dbaa9401b48ed3c17d6578e40b5"
dependencies = [
"cc",
"cmake",
]
[[package]]
name = "spdx"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e1bff9c842210e48eb85ce4c24983b34a481af4ba4b6140b41737e432f4030b"
dependencies = [
"smallvec",
]
[[package]]
name = "syn"
version = "1.0.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "tugger-file-manifest"
version = "0.6.0-pre"
source = "git+https://github.com/ankitects/PyOxidizer.git?rev=ffbfe66912335bc816074c7a08aed06e26bfca7f#ffbfe66912335bc816074c7a08aed06e26bfca7f"
[[package]]
name = "tugger-licensing"
version = "0.5.0-pre"
source = "git+https://github.com/ankitects/PyOxidizer.git?rev=ffbfe66912335bc816074c7a08aed06e26bfca7f#ffbfe66912335bc816074c7a08aed06e26bfca7f"
dependencies = [
"anyhow",
"spdx",
]
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "unindent"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f14ee04d9415b52b3aeab06258a3f07093182b88ba0f9b8d203f211a7a7d41c7"
[[package]]
name = "vswhom"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b"
dependencies = [
"libc",
"vswhom-sys",
]
[[package]]
name = "vswhom-sys"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc2f5402d3d0e79a069714f7b48e3ecc60be7775a2c049cb839457457a239532"
dependencies = [
"cc",
"libc",
]
[[package]]
name = "walkdir"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
dependencies = [
"same-file",
"winapi",
"winapi-util",
]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "winreg"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
dependencies = [
"winapi",
]

52
qt/package/Cargo.toml Normal file
View file

@ -0,0 +1,52 @@
[package]
name = "anki"
version = "0.1.0"
build = "build.rs"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies.pyembed]
git = "https://github.com/ankitects/PyOxidizer.git"
rev = "ffbfe66912335bc816074c7a08aed06e26bfca7f"
default-features = false
[dependencies.jemallocator]
version = "0.3"
optional = true
[dependencies.mimalloc]
version = "0.1"
optional = true
features = ["local_dynamic_tls", "override", "secure"]
[dependencies.snmalloc-rs]
version = "0.2"
optional = true
[build-dependencies]
embed-resource = "1.6"
[features]
default = ["build-mode-standalone"]
global-allocator-jemalloc = ["jemallocator"]
global-allocator-mimalloc = ["mimalloc"]
global-allocator-snmalloc = ["snmalloc-rs"]
allocator-jemalloc = ["pyembed/allocator-jemalloc"]
allocator-mimalloc = ["pyembed/allocator-mimalloc"]
allocator-snmalloc = ["pyembed/allocator-snmalloc"]
# Build this crate in isolation, without using PyOxidizer.
build-mode-standalone = []
# Build this crate by executing a `pyoxidizer` executable to build
# required artifacts.
build-mode-pyoxidizer-exe = []
# Build this crate by reusing artifacts generated by `pyoxidizer` out-of-band.
# In this mode, the PYOXIDIZER_ARTIFACT_DIR environment variable can refer
# to the directory containing build artifacts produced by `pyoxidizer`. If not
# set, OUT_DIR will be used.
build-mode-prebuilt-artifacts = []

BIN
qt/package/anki-icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

View file

@ -0,0 +1,3 @@
#define RT_MANIFEST 24
1 RT_MANIFEST "anki.exe.manifest"
IDI_ICON1 ICON DISCARDABLE "anki-icon.ico"

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
<ws2:longPathAware>true</ws2:longPathAware>
</windowsSettings>
</application>
</assembly>

21
qt/package/build.bat Executable file
View file

@ -0,0 +1,21 @@
:: ensure wheels are built
pushd ..\..
call scripts\build || exit /b
set ROOT=%CD%
popd
:: ensure venv exists
set OUTPUT_ROOT=%ROOT%/bazel-pkg
set VENV=%OUTPUT_ROOT%/venv
if not exist %VENV% (
mkdir %OUTPUT_ROOT%
pushd %ROOT%
call scripts\python -m venv %VENV% || exit /b
popd
)
:: run the rest of the build in Python
FOR /F "tokens=*" %%g IN ('call ..\..\bazel.bat info output_base --ui_event_filters=-INFO') do (SET BAZEL_EXTERNAL=%%g/external)
call %ROOT%\scripts\cargo-env
call ..\..\bazel.bat query @pyqt515//:*
%VENV%\scripts\python build.py %ROOT% %BAZEL_EXTERNAL% || exit /b

226
qt/package/build.py Normal file
View file

@ -0,0 +1,226 @@
# Copyright: Ankitects Pty Ltd and contributors
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import glob
import os
import platform
import re
import shutil
import subprocess
import sys
from pathlib import Path
is_win = sys.platform == "win32"
workspace = Path(sys.argv[1])
output_root = workspace / "bazel-pkg"
dist_folder = output_root / "dist"
venv = output_root / "venv"
cargo_target = output_root / "target"
bazel_external = Path(sys.argv[2])
artifacts = output_root / "artifacts"
pyo3_config = output_root / "pyo3-build-config-file.txt"
if is_win:
python_bin_folder = venv / "scripts"
os.environ["PATH"] = os.getenv("USERPROFILE") + r"\.cargo\bin;" + os.getenv("PATH")
cargo_features = "build-mode-prebuilt-artifacts"
else:
python_bin_folder = venv / "bin"
os.environ["PATH"] = os.getenv("HOME") + "/.cargo/bin:" + os.getenv("PATH")
cargo_features = (
"build-mode-prebuilt-artifacts global-allocator-jemalloc allocator-jemalloc"
)
os.environ["PYOXIDIZER_ARTIFACT_DIR"] = str(artifacts)
os.environ["PYOXIDIZER_CONFIG"] = str(Path(os.getcwd()) / "pyoxidizer.bzl")
os.environ["CARGO_TARGET_DIR"] = str(cargo_target)
# OS-specific things
pyqt5_folder_name = "pyqt515"
if is_win:
os.environ["TARGET"] = "x86_64-pc-windows-msvc"
elif sys.platform.startswith("darwin"):
if platform.machine() == "arm64":
pyqt5_folder_name = None
os.environ["TARGET"] = "aarch64-apple-darwin"
os.environ["MACOSX_DEPLOYMENT_TARGET"] = "11.0"
else:
pyqt5_folder_name = "pyqt514"
os.environ["TARGET"] = "x86_64-apple-darwin"
os.environ["MACOSX_DEPLOYMENT_TARGET"] = "10.13"
else:
if platform.machine() == "x86_64":
os.environ["TARGET"] = "x86_64-unknown-linux-gnu"
else:
os.environ["TARGET"] = "aarch64-unknown-linux-gnu"
raise Exception("building on this architecture is not currently supported")
python = python_bin_folder / "python"
pip = python_bin_folder / "pip"
artifacts_in_build = (
output_root
/ "build"
/ os.getenv("TARGET")
/ "release"
/ "resources"
/ "extra_files"
)
def build_pyoxidizer():
subprocess.run(
[
"cargo",
"install",
"--locked",
"--git",
"https://github.com/ankitects/PyOxidizer.git",
"--rev",
"ffbfe66912335bc816074c7a08aed06e26bfca7f",
"pyoxidizer",
],
check=True,
)
def install_wheels_into_venv():
# Pip's handling of hashes is somewhat broken. It spots the hashes in the constraints
# file and forces all files to have a hash. We can manually hash our generated wheels
# and pass them in with hashes, but it still breaks, because the 'protobuf>=3.17'
# specifier in the pylib wheel is not allowed. Nevermind that a specific version is
# included in the constraints file we pass along! To get things working, we're
# forced to strip the hashes out before installing. This should be safe, as the files
# have already been validated as part of the build process.
constraints = output_root / "deps_without_hashes.txt"
with open(workspace / "python" / "requirements.txt") as f:
buf = f.read()
with open(constraints, "w") as f:
extracted = re.findall("^(\S+==\S+) ", buf, flags=re.M)
f.write("\n".join(extracted))
# install wheels and upgrade any deps
wheels = glob.glob(str(workspace / "bazel-dist" / "*.whl"))
subprocess.run(
[pip, "install", "--upgrade", "-c", constraints, *wheels], check=True
)
# always reinstall our wheels
subprocess.run(
[pip, "install", "--force-reinstall", "--no-deps", *wheels], check=True
)
def build_artifacts():
if os.path.exists(artifacts):
shutil.rmtree(artifacts)
if os.path.exists(artifacts_in_build):
shutil.rmtree(artifacts_in_build)
subprocess.run(
[
"pyoxidizer",
"--system-rust",
"run-build-script",
"build.rs",
"--var",
"venv",
venv,
],
check=True,
env=os.environ
| dict(
CARGO_MANIFEST_DIR=".",
OUT_DIR=str(artifacts),
PROFILE="release",
PYO3_PYTHON=str(python),
),
)
existing_config = None
if os.path.exists(pyo3_config):
with open(pyo3_config) as f:
existing_config = f.read()
with open(artifacts / "pyo3-build-config-file.txt") as f:
new_config = f.read()
# avoid bumping mtime, which triggers crate recompile
if new_config != existing_config:
with open(pyo3_config, "w") as f:
f.write(new_config)
def build_pkg():
subprocess.run(
[
"cargo",
"build",
"--release",
"--no-default-features",
"--features",
cargo_features,
],
check=True,
env=os.environ | dict(PYO3_CONFIG_FILE=str(pyo3_config)),
)
def adj_path_for_windows_rsync(path: Path) -> str:
if not is_win:
return str(path)
path = path.absolute()
rest = str(path)[2:].replace("\\", "/")
return f"/{path.drive[0]}{rest}"
def merge_into_dist(output_folder: Path, pyqt_src_path: Path):
if not output_folder.exists():
output_folder.mkdir(parents=True)
# PyQt
subprocess.run(
[
"rsync",
"-a",
"--delete",
"--exclude-from",
"qt.exclude",
adj_path_for_windows_rsync(pyqt_src_path),
adj_path_for_windows_rsync(output_folder / "lib") + "/",
],
check=True,
)
# Executable and other resources
resources = [
adj_path_for_windows_rsync(
cargo_target / "release" / ("anki.exe" if is_win else "anki")
),
adj_path_for_windows_rsync(artifacts_in_build) + "/",
]
if is_win:
resources.append(adj_path_for_windows_rsync(Path("win")) + "/")
subprocess.run(
[
"rsync",
"-a",
"--delete",
"--exclude",
"PyQt6",
"--exclude",
"PyQt5",
*resources,
adj_path_for_windows_rsync(output_folder) + "/",
],
check=True,
)
build_pyoxidizer()
install_wheels_into_venv()
build_artifacts()
build_pkg()
merge_into_dist(dist_folder / "std", bazel_external / "pyqt6" / "PyQt6")
if pyqt5_folder_name:
merge_into_dist(dist_folder / "alt", bazel_external / pyqt5_folder_name / "PyQt5")

109
qt/package/build.rs Normal file
View file

@ -0,0 +1,109 @@
// Based off PyOxidizer's 'init-rust-project'.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
use {
embed_resource,
std::path::{Path, PathBuf},
};
const DEFAULT_PYTHON_CONFIG_FILENAME: &str = "default_python_config.rs";
const DEFAULT_PYTHON_CONFIG: &str = "\
pub fn default_python_config<'a>() -> pyembed::OxidizedPythonInterpreterConfig<'a> {
pyembed::OxidizedPythonInterpreterConfig::default()
}
";
/// Build with PyOxidizer artifacts in a directory.
fn build_with_artifacts_in_dir(path: &Path) {
println!("using pre-built artifacts from {}", path.display());
let config_path = path.join(DEFAULT_PYTHON_CONFIG_FILENAME);
if !config_path.exists() {
panic!(
"{} does not exist; is {} a valid artifacts directory?",
config_path.display(),
path.display()
);
}
println!(
"cargo:rustc-env=DEFAULT_PYTHON_CONFIG_RS={}",
config_path.display()
);
}
/// Build by calling a `pyoxidizer` executable to generate build artifacts.
fn build_with_pyoxidizer_exe(exe: Option<String>, resolve_target: Option<&str>) {
let pyoxidizer_exe = if let Some(path) = exe {
path
} else {
"pyoxidizer".to_string()
};
let mut args = vec!["run-build-script", "build.rs"];
if let Some(target) = resolve_target {
args.push("--target");
args.push(target);
}
match std::process::Command::new(pyoxidizer_exe)
.args(args)
.status()
{
Ok(status) => {
if !status.success() {
panic!("`pyoxidizer run-build-script` failed");
}
}
Err(e) => panic!("`pyoxidizer run-build-script` failed: {}", e.to_string()),
}
}
#[allow(clippy::if_same_then_else)]
fn main() {
if std::env::var("CARGO_FEATURE_BUILD_MODE_STANDALONE").is_ok() {
let path = PathBuf::from(std::env::var("OUT_DIR").expect("OUT_DIR not defined"));
let path = path.join(DEFAULT_PYTHON_CONFIG_FILENAME);
std::fs::write(&path, DEFAULT_PYTHON_CONFIG.as_bytes())
.expect("failed to write default python config");
println!(
"cargo:rustc-env=DEFAULT_PYTHON_CONFIG_RS={}",
path.display()
);
} else if std::env::var("CARGO_FEATURE_BUILD_MODE_PYOXIDIZER_EXE").is_ok() {
let target = if let Ok(target) = std::env::var("PYOXIDIZER_BUILD_TARGET") {
Some(target)
} else {
None
};
build_with_pyoxidizer_exe(
std::env::var("PYOXIDIZER_EXE").ok(),
target.as_ref().map(|target| target.as_ref()),
);
} else if std::env::var("CARGO_FEATURE_BUILD_MODE_PREBUILT_ARTIFACTS").is_ok() {
let artifact_dir_env = std::env::var("PYOXIDIZER_ARTIFACT_DIR");
let artifact_dir_path = match artifact_dir_env {
Ok(ref v) => PathBuf::from(v),
Err(_) => {
let out_dir = std::env::var("OUT_DIR").unwrap();
PathBuf::from(&out_dir)
}
};
println!("cargo:rerun-if-env-changed=PYOXIDIZER_ARTIFACT_DIR");
build_with_artifacts_in_dir(&artifact_dir_path);
} else {
panic!("build-mode-* feature not set");
}
let target_family =
std::env::var("CARGO_CFG_TARGET_FAMILY").expect("CARGO_CFG_TARGET_FAMILY not defined");
// embed manifest and icon
if target_family == "windows" {
embed_resource::compile("anki-manifest.rc");
}
}

29
qt/package/build.sh Executable file
View file

@ -0,0 +1,29 @@
#!/bin/bash
set -e
cd $(dirname $0)
ROOT=$(pwd)/../..
OUTPUT_ROOT=$ROOT/bazel-pkg
VENV=$OUTPUT_ROOT/venv
BAZEL_EXTERNAL=$(bazel info output_base --ui_event_filters=-INFO)/external
# ensure the wheels are built
(cd $ROOT && ./scripts/build)
# ensure venv exists
test -d $VENV || (
mkdir -p $OUTPUT_ROOT
(cd $ROOT && ./scripts/python -m venv $VENV)
)
# run the rest of the build in Python
. $ROOT/scripts/cargo-env
if [[ "$OSTYPE" == "darwin"* ]]; then
if [ $(uname -m) != "arm64" ]; then
bazel query @pyqt514//:* > /dev/null
fi
else
bazel query @pyqt515//:* > /dev/null
fi
$VENV/bin/python build.py $ROOT $BAZEL_EXTERNAL

162
qt/package/pyoxidizer.bzl Normal file
View file

@ -0,0 +1,162 @@
set_build_path("../../bazel-pkg/build")
excluded_source_prefixes = [
"ctypes.test",
"distutils.tests",
"idlelib",
"lib2to3.tests",
"test",
"tkinter",
"win32comext",
"win32com",
"win32",
"pythonwin",
]
excluded_resource_suffixes = [
".pyi",
".pyc",
"py.typed",
]
included_resource_packages = [
"anki",
"aqt",
"lib2to3",
"certifi",
"jsonschema",
]
def handle_resource(policy, resource):
if type(resource) == "PythonModuleSource":
resource.add_include = True
for prefix in excluded_source_prefixes:
if resource.name.startswith(prefix):
resource.add_include = False
# if resource.add_include:
# print("src", resource.name, resource.add_include)
elif type(resource) == "PythonExtensionModule":
resource.add_include = True
if resource.name.startswith("win32"):
resource.add_include = False
#print("ext", resource.name, resource.add_include)
elif type(resource) == "PythonPackageResource":
for prefix in included_resource_packages:
if resource.package.startswith(prefix):
resource.add_include = True
for suffix in excluded_resource_suffixes:
if resource.name.endswith(suffix):
resource.add_include = False
# aqt web resources can be stored in binary
if resource.package == "aqt":
if not resource.name.startswith("data/web"):
resource.add_location = "filesystem-relative:lib"
# if resource.add_include:
# print("rsrc", resource.package, resource.name, resource.add_include)
elif type(resource) == "PythonPackageDistributionResource":
#print("dist", resource.package, resource.name, resource.add_include)
pass
# elif type(resource) == "File":
# print(resource.path)
elif type(resource) == "File":
if (
resource.path.startswith("win32") or
resource.path.startswith("pythonwin") or
resource.path.startswith("pywin32")
):
exclude = (
"tests" in resource.path or
"benchmark" in resource.path or
"__pycache__" in resource.path
)
if not exclude:
resource.add_include = True
resource.add_location = "filesystem-relative:lib"
if ".dist-info" in resource.path:
resource.add_include = False
else:
print("unexpected type", type(resource))
def make_exe():
if BUILD_TARGET_TRIPLE == "aarch64-unknown-linux-gnu":
fail("arm64 is not currently supported")
elif BUILD_TARGET_TRIPLE == "x86_64-unknown-linux-gnu":
dist = PythonDistribution(
url = "https://github.com/ankitects/python-build-standalone/releases/download/anki-2021-10-15/cpython-3.9.7-x86_64-unknown-linux-gnu-pgo-20211013T1538.tar.zst",
sha256 = "e5341c8f0fbedf83a2246cd86d60b6598033599ae20602d2f80617a304ef3085",
)
else:
dist = default_python_distribution()
policy = dist.make_python_packaging_policy()
policy.file_scanner_classify_files = True
policy.include_classified_resources = False
policy.allow_files = True
policy.file_scanner_emit_files = True
policy.include_file_resources = False
policy.include_distribution_sources = False
policy.include_distribution_resources = False
policy.include_non_distribution_sources = False
policy.include_test = False
policy.resources_location = "in-memory"
policy.resources_location_fallback = "filesystem-relative:lib"
policy.register_resource_callback(handle_resource)
policy.bytecode_optimize_level_zero = False
policy.bytecode_optimize_level_two = True
python_config = dist.make_python_interpreter_config()
# detected libs do not need this, but we add extra afterwards
python_config.module_search_paths = ["$ORIGIN/lib"]
python_config.optimization_level = 2
python_config.run_command = "import aqt; aqt.run()"
exe = dist.to_python_executable(
name = "anki",
packaging_policy = policy,
config = python_config,
)
exe.windows_runtime_dlls_mode = "always"
# set in main.rs
exe.windows_subsystem = "console"
venv_path = "venv"
resources = exe.read_virtualenv(VARS.get("venv"))
exe.add_python_resources(resources)
return exe
def make_embedded_resources(exe):
return exe.to_embedded_resources()
def make_install(exe):
files = FileManifest()
files.add_python_resource(".", exe)
return files
register_target("exe", make_exe)
register_target("resources", make_embedded_resources, depends = ["exe"], default_build_script = True)
register_target("install", make_install, depends = ["exe"], default = True)
resolve_targets()

9
qt/package/qt.exclude Normal file
View file

@ -0,0 +1,9 @@
qml
bindings
uic
lupdate
qsci
*.pyc
*.pyi
*.sip
py.typed

30
qt/package/src/main.rs Normal file
View file

@ -0,0 +1,30 @@
// Based off PyOxidizer's 'init-rust-project'.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
#![windows_subsystem = "console"]
use pyembed::{MainPythonInterpreter, OxidizedPythonInterpreterConfig};
#[cfg(feature = "global-allocator-jemalloc")]
#[global_allocator]
static GLOBAL: jemallocator::Jemalloc = jemallocator::Jemalloc;
include!(env!("DEFAULT_PYTHON_CONFIG_RS"));
fn main() {
println!("Anki starting...");
let exit_code = {
let config: OxidizedPythonInterpreterConfig = default_python_config();
match MainPythonInterpreter::new(config) {
Ok(interp) => interp.run(),
Err(msg) => {
eprintln!("error instantiating embedded Python interpreter: {}", msg);
1
}
}
};
std::process::exit(exit_code);
}

View file

@ -33,6 +33,7 @@ if __name__ == "__main__":
"aqt", "aqt",
"tests", "tests",
"tools", "tools",
"package",
] ]
+ args, + args,
check=False, check=False,
@ -50,6 +51,7 @@ if __name__ == "__main__":
"aqt", "aqt",
"tests", "tests",
"tools", "tools",
"package",
] ]
+ args, + args,
check=False, check=False,

View file

@ -2,7 +2,7 @@
Dependencies required to build Anki. Dependencies required to build Anki.
""" """
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive", "http_file")
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository", "new_git_repository") load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository", "new_git_repository")
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")

View file

@ -7,9 +7,6 @@ if not exist WORKSPACE (
rd /s /q bazel-dist rd /s /q bazel-dist
set BUILDARGS=-k -c opt dist --color=yes --@rules_rust//worker:use_worker=False set BUILDARGS=-k -c opt dist --color=yes
call .\bazel build %BUILDARGS% call .\bazel build %BUILDARGS% || exit /b 1
:: repeat on failure tar xvf bazel-bin\dist.tar || exit /b 1
IF %ERRORLEVEL% NEQ 0 call .\bazel build %BUILDARGS%
tar xvf bazel-bin\dist.tar

View file

@ -1,14 +1,13 @@
#!/bin/bash #!/bin/bash
# Put our vendored version of cargo on the path. Not used by our # Put our vendored version of cargo on the path. Can be helpful if you need
# build scripts, but can be helpful if you need quick access to cargo # quick access to cargo on a machine that does not have Rust installed
# on a machine that does not have Rust installed separately, or # separately, or want to run a quick check. Eg:
# want to run a quick check. Eg:
# $ . scripts/cargo-env # $ . scripts/cargo-env
# $ (cd rslib && cargo check) # $ (cd rslib && cargo check)
BAZEL_EXTERNAL=$(bazel info output_base)/external BAZEL_EXTERNAL=$(bazel info output_base --ui_event_filters=-INFO)/external
if [[ "$OSTYPE" == "darwin"* ]]; then if [[ "$OSTYPE" == "darwin"* ]]; then
if [ "$(arch)" == "i386" ]; then if [ "$(arch)" == "i386" ]; then
@ -17,5 +16,9 @@ if [[ "$OSTYPE" == "darwin"* ]]; then
export PATH="$BAZEL_EXTERNAL/rust_darwin_arm64/bin:$PATH" export PATH="$BAZEL_EXTERNAL/rust_darwin_arm64/bin:$PATH"
fi fi
else else
if [ "$(arch)" == "aarch64" ]; then
export PATH="$BAZEL_EXTERNAL/rust_linux_aarch64/bin:$PATH"
else
export PATH="$BAZEL_EXTERNAL/rust_linux_x86_64/bin:$PATH" export PATH="$BAZEL_EXTERNAL/rust_linux_x86_64/bin:$PATH"
fi
fi fi

2
scripts/cargo-env.bat Normal file
View file

@ -0,0 +1,2 @@
FOR /F "tokens=*" %%g IN ('call ..\..\bazel.bat info output_base --ui_event_filters=-INFO') do (SET BAZEL_EXTERNAL=%%g/external)
set PATH=%BAZEL_EXTERNAL%\rust_windows_x86_64\bin;%PATH%

View file

@ -14,6 +14,8 @@ nonstandard_header = {
"python/pyqt/install.py", "python/pyqt/install.py",
"qt/aqt/mpv.py", "qt/aqt/mpv.py",
"qt/aqt/winpaths.py", "qt/aqt/winpaths.py",
"qt/package/build.rs",
"qt/package/src/main.rs",
} }
ignored_folders = [ ignored_folders = [

View file

@ -6,6 +6,7 @@ ARG gid=1000
RUN apt-get update \ RUN apt-get update \
&& apt-get install --yes --no-install-recommends \ && apt-get install --yes --no-install-recommends \
autoconf \
bash \ bash \
ca-certificates \ ca-certificates \
curl \ curl \
@ -33,6 +34,7 @@ RUN apt-get update \
libxrandr2 \ libxrandr2 \
libxrender1 \ libxrender1 \
libxtst6 \ libxtst6 \
make \
pkg-config \ pkg-config \
portaudio19-dev \ portaudio19-dev \
rsync \ rsync \

View file

@ -6,6 +6,7 @@ ARG gid=1000
RUN apt-get update \ RUN apt-get update \
&& apt-get install --yes --no-install-recommends \ && apt-get install --yes --no-install-recommends \
autoconf \
bash \ bash \
ca-certificates \ ca-certificates \
curl \ curl \
@ -33,6 +34,7 @@ RUN apt-get update \
libxrandr2 \ libxrandr2 \
libxrender1 \ libxrender1 \
libxtst6 \ libxtst6 \
make \
pkg-config \ pkg-config \
portaudio19-dev \ portaudio19-dev \
rsync \ rsync \

View file

@ -3,8 +3,10 @@
set -e set -e
rm -rf bazel-dist rm -rf bazel-dist
bazel --output_user_root=bazel-docker/root \ bazel build -c opt dist --symlink_prefix=bazel-docker/links/ \
build -c opt dist --symlink_prefix=bazel-docker/links/ \
--experimental_no_product_name_out_symlink --experimental_no_product_name_out_symlink
tar xvf bazel-docker/links/bin/dist.tar tar xvf bazel-docker/links/bin/dist.tar
bazel --output_user_root=bazel-docker/root shutdown if [ "$PACKAGE" != "" ]; then
(cd qt/package && ./build.sh)
fi
bazel shutdown

View file

@ -21,6 +21,6 @@ export DOCKER_BUILDKIT=1
docker build --tag ankibuild --file scripts/docker/Dockerfile.$arch \ docker build --tag ankibuild --file scripts/docker/Dockerfile.$arch \
--build-arg uid=$(id -u) --build-arg gid=$(id -g) \ --build-arg uid=$(id -u) --build-arg gid=$(id -g) \
scripts/docker scripts/docker
docker run --rm -it \ docker run --rm -it -e PACKAGE=$PACKAGE \
--mount type=bind,source="$(pwd)",target=/code \ --mount type=bind,source="$(pwd)",target=/code \
ankibuild ankibuild

View file

@ -1,3 +1,3 @@
#!/bin/bash #!/bin/bash
bazel run python -- $* bazel run python --ui_event_filters=-INFO -- $*

1
scripts/python.bat Executable file
View file

@ -0,0 +1 @@
call bazel run python --ui_event_filters=-INFO -- %*