diff --git a/.dprint.json b/.dprint.json index 8e9f19b40..4230cdcd6 100644 --- a/.dprint.json +++ b/.dprint.json @@ -20,7 +20,6 @@ "ftl/usage", "licenses.json", ".dmypy.json", - "qt/bundle/PyOxidizer", "target", ".mypy_cache", "extra", diff --git a/.isort.cfg b/.isort.cfg index 109f5c21e..a26991a95 100644 --- a/.isort.cfg +++ b/.isort.cfg @@ -2,4 +2,3 @@ py_version=39 known_first_party=anki,aqt,tests profile=black -extend_skip=qt/bundle diff --git a/.mypy.ini b/.mypy.ini index 648c6a6ea..5a097cff3 100644 --- a/.mypy.ini +++ b/.mypy.ini @@ -18,7 +18,7 @@ mypy_path = ftl, pylib/tools, python -exclude = (qt/bundle/PyOxidizer|pylib/anki/_vendor) +exclude = (pylib/anki/_vendor) [mypy-anki.*] disallow_untyped_defs = True diff --git a/.ruff.toml b/.ruff.toml index 498ecbdac..fb6ffa2d8 100644 --- a/.ruff.toml +++ b/.ruff.toml @@ -1,2 +1,2 @@ target-version = "py39" -extend-exclude = ["qt/bundle"] +extend-exclude = [] diff --git a/.vscode.dist/settings.json b/.vscode.dist/settings.json index ffac17cae..eb56be7f3 100644 --- a/.vscode.dist/settings.json +++ b/.vscode.dist/settings.json @@ -31,8 +31,7 @@ "rust-analyzer.rustfmt.extraArgs": ["+nightly"], "search.exclude": { "**/node_modules": true, - ".bazel/**": true, - "qt/bundle/PyOxidizer": true + ".bazel/**": true }, "rust-analyzer.cargo.buildScripts.enable": true, "python.analysis.typeCheckingMode": "off", diff --git a/Cargo.lock b/Cargo.lock index 83b636dbc..37fcc0662 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -292,18 +292,6 @@ version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" -[[package]] -name = "apple-bundles" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "716b8a7bacf7325eb3e7a1a7f5ead4da91e1e16d9b56a25edea0e1e4ba21fd8e" -dependencies = [ - "anyhow", - "plist", - "simple-file-manifest", - "walkdir", -] - [[package]] name = "arbitrary" version = "1.4.1" @@ -539,12 +527,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - [[package]] name = "base64" version = "0.21.7" @@ -631,15 +613,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "block-padding" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" -dependencies = [ - "generic-array", -] - [[package]] name = "bstr" version = "1.12.0" @@ -1002,15 +975,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" -[[package]] -name = "cbc" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" -dependencies = [ - "cipher", -] - [[package]] name = "cc" version = "1.2.20" @@ -1073,16 +1037,6 @@ dependencies = [ "half", ] -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", -] - [[package]] name = "clap" version = "4.5.37" @@ -1839,15 +1793,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "des" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffdd80ce8ce993de27e9f063a444a4d53ce8e8db4c1f00cc03af5ad5a9867a1e" -dependencies = [ - "cipher", -] - [[package]] name = "difflib" version = "0.4.0" @@ -1942,18 +1887,6 @@ dependencies = [ "dtoa", ] -[[package]] -name = "duct" -version = "0.13.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ab5718d1224b63252cd0c6f74f6480f9ffeb117438a2e0f5cf6d9a4798929c" -dependencies = [ - "libc", - "once_cell", - "os_pipe", - "shared_child", -] - [[package]] name = "dunce" version = "1.0.5" @@ -2123,17 +2056,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "find-winsdk" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8cbf17b871570c1f8612b763bac3e86290602bcf5dc3c5ce657e0e1e9071d9e" -dependencies = [ - "serde", - "serde_derive", - "winreg 0.5.1", -] - [[package]] name = "fixedbitset" version = "0.5.7" @@ -2273,16 +2195,6 @@ dependencies = [ "thiserror 1.0.69", ] -[[package]] -name = "fs2" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "fsevent-sys" version = "4.1.0" @@ -3187,20 +3099,6 @@ dependencies = [ "want", ] -[[package]] -name = "hyper-rustls" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" -dependencies = [ - "futures-util", - "http 0.2.12", - "hyper 0.14.32", - "rustls 0.21.12", - "tokio", - "tokio-rustls 0.24.1", -] - [[package]] name = "hyper-rustls" version = "0.27.5" @@ -3211,13 +3109,13 @@ dependencies = [ "http 1.3.1", "hyper 1.6.0", "hyper-util", - "rustls 0.23.26", + "rustls", "rustls-native-certs", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.2", + "tokio-rustls", "tower-service", - "webpki-roots 0.26.8", + "webpki-roots", ] [[package]] @@ -3505,16 +3403,6 @@ dependencies = [ "libc", ] -[[package]] -name = "inout" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" -dependencies = [ - "block-padding", - "generic-array", -] - [[package]] name = "intl-memoizer" version = "0.5.2" @@ -3883,33 +3771,6 @@ dependencies = [ "syn 2.0.101", ] -[[package]] -name = "makeapp" -version = "0.0.0" -dependencies = [ - "anyhow", - "apple-bundles", - "camino", - "clap", - "glob", - "plist", - "serde", - "serde_json", - "simple-file-manifest", - "walkdir", -] - -[[package]] -name = "makeexe" -version = "0.0.0" -dependencies = [ - "anyhow", - "camino", - "clap", - "tugger-windows-codesign", - "walkdir", -] - [[package]] name = "malloc_buf" version = "0.0.6" @@ -4623,39 +4484,12 @@ dependencies = [ "num-traits", ] -[[package]] -name = "os_pipe" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - [[package]] name = "overload" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" -[[package]] -name = "p12" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4873306de53fe82e7e484df31e1e947d61514b6ea2ed6cd7b45d63006fd9224" -dependencies = [ - "cbc", - "cipher", - "des", - "getrandom 0.2.16", - "hmac", - "lazy_static", - "rc2", - "sha1", - "yasna", -] - [[package]] name = "parking" version = "2.2.1" @@ -4720,15 +4554,6 @@ dependencies = [ "sha2", ] -[[package]] -name = "pem" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" -dependencies = [ - "base64 0.13.1", -] - [[package]] name = "percent-encoding" version = "2.3.1" @@ -4923,19 +4748,6 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" -[[package]] -name = "plist" -version = "1.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d77244ce2d584cd84f6a15f86195b8c9b2a0dfbfd817c09e0464244091a58ed" -dependencies = [ - "base64 0.22.1", - "indexmap", - "quick-xml", - "serde", - "time", -] - [[package]] name = "plotters" version = "0.3.7" @@ -5254,15 +5066,6 @@ dependencies = [ "syn 2.0.101", ] -[[package]] -name = "quick-xml" -version = "0.37.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb" -dependencies = [ - "memchr", -] - [[package]] name = "quinn" version = "0.11.7" @@ -5275,7 +5078,7 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash 2.1.1", - "rustls 0.23.26", + "rustls", "socket2", "thiserror 2.0.12", "tokio", @@ -5292,9 +5095,9 @@ dependencies = [ "bytes", "getrandom 0.3.2", "rand 0.9.1", - "ring 0.17.14", + "ring", "rustc-hash 2.1.1", - "rustls 0.23.26", + "rustls", "rustls-pki-types", "slab", "thiserror 2.0.12", @@ -5467,27 +5270,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "rc2" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62c64daa8e9438b84aaae55010a93f396f8e60e3911590fcba770d04643fc1dd" -dependencies = [ - "cipher", -] - -[[package]] -name = "rcgen" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" -dependencies = [ - "pem", - "ring 0.16.20", - "time", - "yasna", -] - [[package]] name = "reborrow" version = "0.5.5" @@ -5596,7 +5378,6 @@ dependencies = [ "http 0.2.12", "http-body 0.4.6", "hyper 0.14.32", - "hyper-rustls 0.24.2", "hyper-tls 0.5.0", "ipnet", "js-sys", @@ -5606,7 +5387,6 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls 0.21.12", "rustls-pemfile 1.0.4", "serde", "serde_json", @@ -5615,14 +5395,12 @@ dependencies = [ "system-configuration", "tokio", "tokio-native-tls", - "tokio-rustls 0.24.1", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 0.25.4", - "winreg 0.50.0", + "winreg", ] [[package]] @@ -5640,7 +5418,7 @@ dependencies = [ "http-body 1.0.1", "http-body-util", "hyper 1.6.0", - "hyper-rustls 0.27.5", + "hyper-rustls", "hyper-tls 0.6.0", "hyper-util", "ipnet", @@ -5653,7 +5431,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.26", + "rustls", "rustls-native-certs", "rustls-pemfile 2.2.0", "rustls-pki-types", @@ -5663,7 +5441,7 @@ dependencies = [ "sync_wrapper 1.0.2", "tokio", "tokio-native-tls", - "tokio-rustls 0.26.2", + "tokio-rustls", "tokio-socks", "tokio-util", "tower", @@ -5673,25 +5451,10 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots 0.26.8", + "webpki-roots", "windows-registry", ] -[[package]] -name = "ring" -version = "0.16.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin 0.5.2", - "untrusted 0.7.1", - "web-sys", - "winapi", -] - [[package]] name = "ring" version = "0.17.14" @@ -5702,7 +5465,7 @@ dependencies = [ "cfg-if", "getrandom 0.2.16", "libc", - "untrusted 0.9.0", + "untrusted", "windows-sys 0.52.0", ] @@ -5855,18 +5618,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "rustls" -version = "0.21.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" -dependencies = [ - "log", - "ring 0.17.14", - "rustls-webpki 0.101.7", - "sct", -] - [[package]] name = "rustls" version = "0.23.26" @@ -5874,9 +5625,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df51b5869f3a441595eac5e8ff14d486ff285f7b8c0df8770e49c3b56351f0f0" dependencies = [ "once_cell", - "ring 0.17.14", + "ring", "rustls-pki-types", - "rustls-webpki 0.103.1", + "rustls-webpki", "subtle", "zeroize", ] @@ -5920,25 +5671,15 @@ dependencies = [ "web-time", ] -[[package]] -name = "rustls-webpki" -version = "0.101.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" -dependencies = [ - "ring 0.17.14", - "untrusted 0.9.0", -] - [[package]] name = "rustls-webpki" version = "0.103.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03" dependencies = [ - "ring 0.17.14", + "ring", "rustls-pki-types", - "untrusted 0.9.0", + "untrusted", ] [[package]] @@ -6012,16 +5753,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring 0.17.14", - "untrusted 0.9.0", -] - [[package]] name = "security-framework" version = "2.11.1" @@ -6233,16 +5964,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "shared_child" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09fa9338aed9a1df411814a5b2252f7cd206c55ae9bf2fa763f8de84603aa60c" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - [[package]] name = "shlex" version = "1.3.0" @@ -6258,12 +5979,6 @@ dependencies = [ "libc", ] -[[package]] -name = "simple-file-manifest" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dd19be0257552dd56d1bb6946f89f193c6e5b9f13cc9327c4bc84a357507c74" - [[package]] name = "siphasher" version = "0.3.11" @@ -6337,12 +6052,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - [[package]] name = "spin" version = "0.9.8" @@ -6824,23 +6533,13 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-rustls" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" -dependencies = [ - "rustls 0.21.12", - "tokio", -] - [[package]] name = "tokio-rustls" version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" dependencies = [ - "rustls 0.23.26", + "rustls", "tokio", ] @@ -7038,58 +6737,6 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "tugger-common" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90d950380afdb1a6bbe74f29485a04e821869dfad11f5929ff1c5b1dac09d02" -dependencies = [ - "anyhow", - "fs2", - "glob", - "hex", - "log", - "once_cell", - "reqwest 0.11.27", - "sha2", - "tempfile", - "url", - "zip 0.6.6", -] - -[[package]] -name = "tugger-windows" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9f181ac4fc7f8facfd418824d13045cd068ee73de44319a6116868c22789782" -dependencies = [ - "anyhow", - "duct", - "find-winsdk", - "glob", - "once_cell", - "semver", - "tugger-common", - "winapi", -] - -[[package]] -name = "tugger-windows-codesign" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed3f09f8bdace495373cec3fc607bc39f00720a984ba82e310cc9382462fd364" -dependencies = [ - "anyhow", - "duct", - "log", - "p12", - "rcgen", - "time", - "tugger-common", - "tugger-windows", - "yasna", -] - [[package]] name = "tungstenite" version = "0.21.0" @@ -7290,12 +6937,6 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3" -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - [[package]] name = "untrusted" version = "0.9.0" @@ -7566,12 +7207,6 @@ dependencies = [ "string_cache_codegen", ] -[[package]] -name = "webpki-roots" -version = "0.25.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" - [[package]] name = "webpki-roots" version = "0.26.8" @@ -8233,16 +7868,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "winreg" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a27a759395c1195c4cc5cda607ef6f8f6498f64e78f7900f5de0a127a424704a" -dependencies = [ - "serde", - "winapi", -] - [[package]] name = "winreg" version = "0.50.0" @@ -8346,15 +7971,6 @@ dependencies = [ "lzma-sys", ] -[[package]] -name = "yasna" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" -dependencies = [ - "time", -] - [[package]] name = "yoke" version = "0.7.5" diff --git a/Cargo.toml b/Cargo.toml index 483e165f6..7278b5474 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,9 +12,7 @@ members = [ "build/runner", "ftl", "pylib/rsbridge", - "qt/bundle/launcher", - "qt/bundle/mac", - "qt/bundle/win", + "qt/launcher", "rslib", "rslib/i18n", "rslib/io", diff --git a/build/configure/src/aqt.rs b/build/configure/src/aqt.rs index e7849a751..60316fcd2 100644 --- a/build/configure/src/aqt.rs +++ b/build/configure/src/aqt.rs @@ -371,11 +371,7 @@ fn build_wheel(build: &mut Build) -> Result<()> { } fn check_python(build: &mut Build) -> Result<()> { - python_format( - build, - "qt", - inputs![glob!("qt/**/*.py", "qt/bundle/PyOxidizer/**")], - )?; + python_format(build, "qt", inputs![glob!("qt/**/*.py")])?; build.add_action( "check:pytest:aqt", diff --git a/build/configure/src/bundle.rs b/build/configure/src/bundle.rs deleted file mode 100644 index 921b1e825..000000000 --- a/build/configure/src/bundle.rs +++ /dev/null @@ -1,445 +0,0 @@ -// Copyright: Ankitects Pty Ltd and contributors -// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html - -#![allow(dead_code)] -#![allow(unused_imports)] - -use std::env; - -use anyhow::Result; -use ninja_gen::action::BuildAction; -use ninja_gen::archives::download_and_extract; -use ninja_gen::archives::empty_manifest; -use ninja_gen::archives::with_exe; -use ninja_gen::archives::OnlineArchive; -use ninja_gen::archives::Platform; -use ninja_gen::build::BuildProfile; -use ninja_gen::cargo::CargoBuild; -use ninja_gen::cargo::RustOutput; -use ninja_gen::git::SyncSubmodule; -use ninja_gen::glob; -use ninja_gen::input::BuildInput; -use ninja_gen::inputs; -use ninja_gen::python::PythonEnvironment; -use ninja_gen::Build; -use ninja_gen::Utf8Path; - -use crate::anki_version; -use crate::platform::overriden_python_target_platform; -use crate::platform::overriden_rust_target_triple; - -#[derive(Debug, PartialEq, Eq)] -enum DistKind { - Standard, -} - -impl DistKind { - fn folder_name(&self) -> &'static str { - match self { - DistKind::Standard => "std", - } - } - - fn name(&self) -> &'static str { - match self { - DistKind::Standard => "standard", - } - } -} - -pub fn build_bundle(_build: &mut Build) -> Result<()> { - // install into venv - // setup_primary_venv(build)?; - // install_anki_wheels(build)?; - - // // bundle venv into output binary + extra_files - // build_pyoxidizer(build)?; - // build_artifacts(build)?; - // build_binary(build)?; - - // // package up outputs with Qt/other deps - // download_dist_folder_deps(build)?; - // build_dist_folder(build, DistKind::Standard)?; - - // build_packages(build)?; - - Ok(()) -} - -fn targetting_macos_arm() -> bool { - cfg!(all(target_os = "macos", target_arch = "aarch64")) - && overriden_python_target_platform().is_none() -} - -const WIN_AUDIO: OnlineArchive = OnlineArchive { - url: "https://github.com/ankitects/anki-bundle-extras/releases/download/anki-2022-02-09/audio-win-amd64.tar.gz", - sha256: "0815a601baba05e03bc36b568cdc2332b1cf4aa17125fc33c69de125f8dd687f", -}; - -const MAC_ARM_AUDIO: OnlineArchive = OnlineArchive { - url: "https://github.com/ankitects/anki-bundle-extras/releases/download/anki-2022-05-26/audio-mac-arm64.tar.gz", - sha256: "f6c4af9be59ae1c82a16f5c6307f13cbf31b49ad7b69ce1cb6e0e7b403cfdb8f", -}; - -const MAC_AMD_AUDIO: OnlineArchive = OnlineArchive { - url: "https://github.com/ankitects/anki-bundle-extras/releases/download/anki-2022-05-26/audio-mac-amd64.tar.gz", - sha256: "ecbb3c878805cdd58b1a0b8e3fd8c753b8ce3ad36c8b5904a79111f9db29ff42", -}; - -const MAC_ARM_QT6: OnlineArchive = OnlineArchive { - url: "https://github.com/ankitects/anki-bundle-extras/releases/download/anki-2024-02-29/pyqt6.6-mac-arm64.tar.zst", - sha256: "9b2ade4ae9b80506689062845e83e8c60f7fa9843545bf7bb2d11d3e2f105878", -}; - -const MAC_AMD_QT6: OnlineArchive = OnlineArchive { - url: "https://github.com/ankitects/anki-bundle-extras/releases/download/anki-2024-02-29/pyqt6.6-mac-amd64.tar.zst", - sha256: "dbd0871e4da22820d1fa9ab29220d631467d1178038dcab4b15169ad7f499b1b", -}; - -const LINUX_QT_PLUGINS: OnlineArchive = OnlineArchive { - url: "https://github.com/ankitects/anki-bundle-extras/releases/download/anki-2023-05-02/qt-plugins-linux-amd64.tar.gz", - sha256: "66bb568aca7242bc55ad419bf5c96755ca15d2a743e1c3a09cba8b83230b138b", -}; - -const NSIS_PLUGINS: OnlineArchive = OnlineArchive { - url: "https://github.com/ankitects/anki-bundle-extras/releases/download/anki-2023-05-19/nsis.tar.zst", - sha256: "6133f730ece699de19714d0479c73bc848647d277e9cc80dda9b9ebe532b40a8", -}; - -fn download_dist_folder_deps(build: &mut Build) -> Result<()> { - let mut bundle_deps = vec![":wheels"]; - if cfg!(windows) { - download_and_extract(build, "win_amd64_audio", WIN_AUDIO, empty_manifest())?; - download_and_extract(build, "nsis_plugins", NSIS_PLUGINS, empty_manifest())?; - bundle_deps.extend([":extract:win_amd64_audio", ":extract:nsis_plugins"]); - } else if cfg!(target_os = "macos") { - if targetting_macos_arm() { - download_and_extract(build, "mac_arm_audio", MAC_ARM_AUDIO, empty_manifest())?; - download_and_extract(build, "mac_arm_qt6", MAC_ARM_QT6, empty_manifest())?; - bundle_deps.extend([":extract:mac_arm_audio", ":extract:mac_arm_qt6"]); - } else { - download_and_extract(build, "mac_amd_audio", MAC_AMD_AUDIO, empty_manifest())?; - download_and_extract(build, "mac_amd_qt6", MAC_AMD_QT6, empty_manifest())?; - bundle_deps.extend([":extract:mac_amd_audio", ":extract:mac_amd_qt6"]); - } - } else { - download_and_extract( - build, - "linux_qt_plugins", - LINUX_QT_PLUGINS, - empty_manifest(), - )?; - bundle_deps.extend([":extract:linux_qt_plugins"]); - } - build.add_dependency( - "bundle:deps", - inputs![bundle_deps - .iter() - .map(ToString::to_string) - .collect::>()], - ); - Ok(()) -} - -struct Venv { - label: &'static str, - path_without_builddir: &'static str, -} - -impl Venv { - fn label_as_target(&self, suffix: &str) -> String { - format!(":{}{suffix}", self.label) - } -} - -const PRIMARY_VENV: Venv = Venv { - label: "bundle:pyenv", - path_without_builddir: "bundle/pyenv", -}; - -// fn setup_primary_venv(build: &mut Build) -> Result<()> { -// let mut qt6_reqs = inputs![ -// "python/requirements.bundle.txt", -// "python/requirements.qt6_6.txt", -// ]; -// if cfg!(windows) { -// qt6_reqs = inputs![qt6_reqs, "python/requirements.win.txt"]; -// } -// build.add_action( -// PRIMARY_VENV.label, -// PythonEnvironment { -// venv_folder: PRIMARY_VENV.path_without_builddir, -// base_requirements_txt: "python/requirements.base.txt".into(), -// requirements_txt: qt6_reqs, -// extra_binary_exports: &[], -// }, -// )?; -// Ok(()) -// } - -struct InstallAnkiWheels { - venv: Venv, -} - -impl BuildAction for InstallAnkiWheels { - fn command(&self) -> &str { - "$pip install --force-reinstall --no-deps $in" - } - - fn files(&mut self, build: &mut impl ninja_gen::build::FilesHandle) { - build.add_inputs("pip", inputs![self.venv.label_as_target(":pip")]); - build.add_inputs("in", inputs![":wheels"]); - build.add_output_stamp("bundle/wheels.stamp"); - } -} - -fn install_anki_wheels(build: &mut Build) -> Result<()> { - build.add_action( - "bundle:add_wheels:qt6", - InstallAnkiWheels { venv: PRIMARY_VENV }, - )?; - Ok(()) -} - -fn build_pyoxidizer(build: &mut Build) -> Result<()> { - let offline_build = env::var("OFFLINE_BUILD").is_ok(); - - build.add_action( - "bundle:pyoxidizer:repo", - SyncSubmodule { - path: "qt/bundle/PyOxidizer", - offline_build, - }, - )?; - let target = - overriden_rust_target_triple().unwrap_or_else(|| Platform::current().as_rust_triple()); - let output_bin = format!("bundle/rust/{target}/release/pyoxidizer",); - build.add_action( - "bundle:pyoxidizer:bin", - CargoBuild { - inputs: inputs![ - ":bundle:pyoxidizer:repo", - "out/env", - glob!["qt/bundle/PyOxidizer/**"] - ], - // can't use ::Binary() here, as we're in a separate workspace - outputs: &[RustOutput::Data("bin", &with_exe(&output_bin))], - target: Some(target), - extra_args: &format!( - "--manifest-path={} --target-dir={} -p pyoxidizer", - "qt/bundle/PyOxidizer/Cargo.toml", "$builddir/bundle/rust" - ), - release_override: Some(BuildProfile::Release), - }, - )?; - Ok(()) -} - -struct BuildArtifacts {} - -impl BuildAction for BuildArtifacts { - fn command(&self) -> &str { - "$runner build-artifacts $bundle_root $pyoxidizer_bin" - } - - fn files(&mut self, build: &mut impl ninja_gen::build::FilesHandle) { - build.add_inputs("pyoxidizer_bin", inputs![":bundle:pyoxidizer:bin"]); - build.add_inputs("", inputs![PRIMARY_VENV.label_as_target("")]); - build.add_inputs("", inputs![":bundle:add_wheels:qt6", glob!["qt/bundle/**"]]); - build.add_variable("bundle_root", "$builddir/bundle"); - build.add_outputs_ext( - "pyo3_config", - vec!["bundle/artifacts/pyo3-build-config-file.txt"], - true, - ); - } - - fn check_output_timestamps(&self) -> bool { - true - } -} - -fn build_artifacts(build: &mut Build) -> Result<()> { - build.add_action("bundle:artifacts", BuildArtifacts {}) -} - -struct BuildBundle {} - -impl BuildAction for BuildBundle { - fn command(&self) -> &str { - "$runner build-bundle-binary" - } - - fn files(&mut self, build: &mut impl ninja_gen::build::FilesHandle) { - build.add_inputs("", inputs![":bundle:artifacts", glob!["qt/bundle/**"]]); - build.add_outputs( - "", - vec![RustOutput::Binary("anki").path( - Utf8Path::new("$builddir/bundle/rust"), - Some( - overriden_rust_target_triple() - .unwrap_or_else(|| Platform::current().as_rust_triple()), - ), - // our pyoxidizer bin uses lto on the release profile - BuildProfile::Release, - )], - ); - } -} - -fn build_binary(build: &mut Build) -> Result<()> { - build.add_action("bundle:binary", BuildBundle {}) -} - -struct BuildDistFolder { - kind: DistKind, - deps: BuildInput, -} - -impl BuildAction for BuildDistFolder { - fn command(&self) -> &str { - "$runner build-dist-folder $kind $out_folder " - } - - fn files(&mut self, build: &mut impl ninja_gen::build::FilesHandle) { - build.add_inputs("", &self.deps); - build.add_variable("kind", self.kind.name()); - let folder = match self.kind { - DistKind::Standard => "bundle/std", - }; - build.add_outputs("out_folder", vec![folder]); - build.add_outputs("stamp", vec![format!("{folder}.stamp")]); - } - - fn check_output_timestamps(&self) -> bool { - true - } -} - -fn build_dist_folder(build: &mut Build, kind: DistKind) -> Result<()> { - let deps = inputs![":bundle:deps", ":bundle:binary", glob!["qt/bundle/**"]]; - let group = match kind { - DistKind::Standard => "bundle:folder:std", - }; - build.add_action(group, BuildDistFolder { kind, deps }) -} - -fn build_packages(build: &mut Build) -> Result<()> { - if cfg!(windows) { - build_windows_installers(build) - } else if cfg!(target_os = "macos") { - build_mac_app(build, DistKind::Standard)?; - build_dmgs(build) - } else { - build_tarball(build, DistKind::Standard) - } -} - -struct BuildTarball { - kind: DistKind, -} - -impl BuildAction for BuildTarball { - fn command(&self) -> &str { - "chmod -R a+r $folder && tar -I '$zstd' --transform $transform -cf $tarball -C $folder ." - } - - fn files(&mut self, build: &mut impl ninja_gen::build::FilesHandle) { - let input_folder_name = self.kind.folder_name(); - let input_folder_target = format!(":bundle:folder:{input_folder_name}"); - let input_folder_path = format!("$builddir/bundle/{input_folder_name}"); - - let version = anki_version(); - let qt = match self.kind { - DistKind::Standard => "qt6", - }; - let output_folder_base = format!("anki-{version}-linux-{qt}"); - let output_tarball = format!("bundle/package/{output_folder_base}.tar.zst"); - - build.add_inputs("", inputs![input_folder_target]); - build.add_variable("zstd", "zstd -c --long -T0 -18"); - build.add_variable("transform", format!("s%^.%{output_folder_base}%S")); - build.add_variable("folder", input_folder_path); - build.add_outputs("tarball", vec![output_tarball]); - } -} - -fn build_tarball(build: &mut Build, kind: DistKind) -> Result<()> { - let name = kind.folder_name(); - build.add_action(format!("bundle:package:{name}"), BuildTarball { kind }) -} - -struct BuildWindowsInstallers {} - -impl BuildAction for BuildWindowsInstallers { - fn command(&self) -> &str { - "cargo run -p makeexe --target-dir=out/rust -- $version $src_root $bundle_root $out" - } - - fn files(&mut self, build: &mut impl ninja_gen::build::FilesHandle) { - let version = anki_version(); - let outputs = ["qt6"].iter().map(|qt| { - let output_base = format!("anki-{version}-windows-{qt}"); - format!("bundle/package/{output_base}.exe") - }); - - build.add_inputs("", inputs![":bundle:folder:std"]); - build.add_variable("version", &version); - build.add_variable("bundle_root", "$builddir/bundle"); - build.add_outputs("out", outputs); - } -} - -fn build_windows_installers(build: &mut Build) -> Result<()> { - build.add_action("bundle:package", BuildWindowsInstallers {}) -} - -struct BuildMacApp { - kind: DistKind, -} - -impl BuildAction for BuildMacApp { - fn command(&self) -> &str { - "cargo run -p makeapp --target-dir=out/rust -- build-app $version $kind $stamp" - } - - fn files(&mut self, build: &mut impl ninja_gen::build::FilesHandle) { - let folder_name = self.kind.folder_name(); - build.add_inputs("", inputs![format!(":bundle:folder:{folder_name}")]); - build.add_variable("version", anki_version()); - build.add_variable("kind", self.kind.name()); - build.add_outputs("stamp", vec![format!("bundle/app/{folder_name}.stamp")]); - } -} - -fn build_mac_app(build: &mut Build, kind: DistKind) -> Result<()> { - build.add_action(format!("bundle:app:{}", kind.name()), BuildMacApp { kind }) -} - -struct BuildDmgs {} - -impl BuildAction for BuildDmgs { - fn command(&self) -> &str { - "cargo run -p makeapp --target-dir=out/rust -- build-dmgs $dmgs" - } - - fn files(&mut self, build: &mut impl ninja_gen::build::FilesHandle) { - let version = anki_version(); - let platform = if targetting_macos_arm() { - "apple" - } else { - "intel" - }; - let qt = &["qt6"][..]; - let dmgs = qt - .iter() - .map(|qt| format!("bundle/dmg/anki-{version}-mac-{platform}-{qt}.dmg")); - - build.add_inputs("", inputs![":bundle:app"]); - build.add_outputs("dmgs", dmgs); - } -} - -fn build_dmgs(build: &mut Build) -> Result<()> { - build.add_action("bundle:dmg", BuildDmgs {}) -} diff --git a/build/configure/src/launcher.rs b/build/configure/src/launcher.rs new file mode 100644 index 000000000..f8f48ca6a --- /dev/null +++ b/build/configure/src/launcher.rs @@ -0,0 +1,60 @@ +// Copyright: Ankitects Pty Ltd and contributors +// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html + +#![allow(dead_code)] +#![allow(unused_imports)] + +use std::env; + +use anyhow::Result; +use ninja_gen::action::BuildAction; +use ninja_gen::archives::download_and_extract; +use ninja_gen::archives::empty_manifest; +use ninja_gen::archives::with_exe; +use ninja_gen::archives::OnlineArchive; +use ninja_gen::archives::Platform; +use ninja_gen::build::BuildProfile; +use ninja_gen::cargo::CargoBuild; +use ninja_gen::cargo::RustOutput; +use ninja_gen::command::RunCommand; +use ninja_gen::git::SyncSubmodule; +use ninja_gen::glob; +use ninja_gen::hashmap; +use ninja_gen::input::BuildInput; +use ninja_gen::inputs; +use ninja_gen::python::PythonEnvironment; +use ninja_gen::Build; +use ninja_gen::Utf8Path; + +use crate::anki_version; +use crate::platform::overriden_python_target_platform; +use crate::platform::overriden_rust_target_triple; + +pub fn setup_uv_universal(build: &mut Build) -> Result<()> { + build.add_action( + "launcher:uv_universal", + RunCommand { + command: "/usr/bin/lipo", + args: "-create -output $out $arm_bin $x86_bin", + inputs: hashmap! { + "arm_bin" => inputs![":extract:uv:bin"], + "x86_bin" => inputs![":extract:uv_mac_x86:bin"], + }, + outputs: hashmap! { + "out" => vec!["launcher/uv"], + }, + }, + ) +} + +pub fn build_launcher(build: &mut Build) -> Result<()> { + setup_uv_universal(build)?; + download_and_extract(build, "nsis_plugins", NSIS_PLUGINS, empty_manifest())?; + + Ok(()) +} + +const NSIS_PLUGINS: OnlineArchive = OnlineArchive { + url: "https://github.com/ankitects/anki-bundle-extras/releases/download/anki-2023-05-19/nsis.tar.zst", + sha256: "6133f730ece699de19714d0479c73bc848647d277e9cc80dda9b9ebe532b40a8", +}; diff --git a/build/configure/src/main.rs b/build/configure/src/main.rs index d165f767d..1ec0b31ac 100644 --- a/build/configure/src/main.rs +++ b/build/configure/src/main.rs @@ -2,7 +2,7 @@ // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html mod aqt; -mod bundle; +mod launcher; mod platform; mod pylib; mod python; @@ -13,13 +13,12 @@ use std::env; use anyhow::Result; use aqt::build_and_check_aqt; -use bundle::build_bundle; +use launcher::build_launcher; use ninja_gen::glob; use ninja_gen::inputs; use ninja_gen::protobuf::check_proto; use ninja_gen::protobuf::setup_protoc; use ninja_gen::python::setup_uv; -use ninja_gen::python::setup_uv_universal; use ninja_gen::Build; use platform::overriden_python_target_platform; use pylib::build_pylib; @@ -62,8 +61,7 @@ fn main() -> Result<()> { build_and_check_aqt(build)?; if env::var("OFFLINE_BUILD").is_err() { - setup_uv_universal(build)?; - build_bundle(build)?; + build_launcher(build)?; } setup_sphinx(build)?; diff --git a/build/ninja_gen/src/python.rs b/build/ninja_gen/src/python.rs index aea77a22c..0ee44276d 100644 --- a/build/ninja_gen/src/python.rs +++ b/build/ninja_gen/src/python.rs @@ -12,7 +12,6 @@ use crate::archives::download_and_extract; use crate::archives::with_exe; use crate::archives::OnlineArchive; use crate::archives::Platform; -use crate::command::RunCommand; use crate::hash::simple_hash; use crate::input::BuildInput; use crate::inputs; @@ -286,20 +285,3 @@ impl BuildAction for PythonTest { true } } - -pub fn setup_uv_universal(build: &mut Build) -> Result<()> { - build.add_action( - "bundle:uv_universal", - RunCommand { - command: "/usr/bin/lipo", - args: "-create -output $out $arm_bin $x86_bin", - inputs: hashmap! { - "arm_bin" => inputs![":extract:uv:bin"], - "x86_bin" => inputs![":extract:uv_mac_x86:bin"], - }, - outputs: hashmap! { - "out" => vec!["bundle/uv"], - }, - }, - ) -} diff --git a/build/runner/src/bundle/artifacts.rs b/build/runner/src/bundle/artifacts.rs deleted file mode 100644 index ec5506717..000000000 --- a/build/runner/src/bundle/artifacts.rs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright: Ankitects Pty Ltd and contributors -// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html - -use std::env; -use std::fs; -use std::process::Command; - -use camino::Utf8PathBuf; -use clap::Args; - -use crate::run::run_command; - -#[derive(Args, Debug)] -pub struct BuildArtifactsArgs { - bundle_root: Utf8PathBuf, - pyoxidizer_bin: String, -} - -pub fn build_artifacts(args: BuildArtifactsArgs) { - // build.rs doesn't declare inputs from venv, so we need to force a rebuild to - // ensure changes to our libs/the venv get included - let artifacts = args.bundle_root.join("artifacts"); - if artifacts.exists() { - fs::remove_dir_all(&artifacts).unwrap(); - } - let bundle_root = args.bundle_root.canonicalize_utf8().unwrap(); - let build_folder = bundle_root.join("build"); - if build_folder.exists() { - fs::remove_dir_all(&build_folder).unwrap(); - } - - run_command( - Command::new(&args.pyoxidizer_bin) - .args([ - "--system-rust", - "run-build-script", - "qt/bundle/build.rs", - "--var", - "venv", - "out/bundle/pyenv", - "--var", - "build", - build_folder.as_str(), - ]) - .env("CARGO_MANIFEST_DIR", "qt/bundle") - .env("CARGO_TARGET_DIR", "out/bundle/rust") - .env("PROFILE", "release") - .env("OUT_DIR", &artifacts) - .env("TARGET", env!("TARGET")) - .env("SDKROOT", "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk") - .env("MACOSX_DEPLOYMENT_TARGET", macos_deployment_target()) - .env("CARGO_BUILD_TARGET", env!("TARGET")), - ); -} - -pub fn macos_deployment_target() -> &'static str { - if env!("TARGET") == "x86_64-apple-darwin" { - "10.13.4" - } else { - "11" - } -} diff --git a/build/runner/src/bundle/binary.rs b/build/runner/src/bundle/binary.rs deleted file mode 100644 index e9119220a..000000000 --- a/build/runner/src/bundle/binary.rs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright: Ankitects Pty Ltd and contributors -// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html - -use std::process::Command; - -use anki_process::CommandExt; -use camino::Utf8Path; -use camino::Utf8PathBuf; - -use super::artifacts::macos_deployment_target; -use crate::run::run_command; - -pub fn build_bundle_binary() { - let mut features = String::from("build-mode-prebuilt-artifacts"); - if cfg!(target_os = "linux") || cfg!(target_os = "macos") { - features.push_str(",global-allocator-jemalloc,allocator-jemalloc"); - } - - let mut command = Command::new("cargo"); - command - .args([ - "build", - "--manifest-path=qt/bundle/Cargo.toml", - "--target-dir=out/bundle/rust", - "--release", - "--no-default-features", - ]) - .arg(format!("--features={features}")) - .env( - "DEFAULT_PYTHON_CONFIG_RS", - // included in main.rs, so relative to qt/bundle/src - "../../../out/bundle/artifacts/", - ) - .env( - "PYO3_CONFIG_FILE", - Utf8Path::new("out/bundle/artifacts/pyo3-build-config-file.txt") - .canonicalize_utf8() - .unwrap(), - ) - .env("MACOSX_DEPLOYMENT_TARGET", macos_deployment_target()) - .env("SDKROOT", "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk") - .env("CARGO_BUILD_TARGET", env!("TARGET")); - if env!("TARGET") == "x86_64-apple-darwin" { - let xcode_path = Command::run_with_output(["xcode-select", "-p"]).unwrap(); - let ld_classic = Utf8PathBuf::from(xcode_path.stdout.trim()) - .join("Toolchains/XcodeDefault.xctoolchain/usr/bin/ld-classic"); - if ld_classic.exists() { - // work around XCode 15's default linker not supporting macOS 10.15-12. - command.env("RUSTFLAGS", format!("-Clink-arg=-fuse-ld={ld_classic}")); - } - } - run_command(&mut command); -} diff --git a/build/runner/src/bundle/folder.rs b/build/runner/src/bundle/folder.rs deleted file mode 100644 index cdbfd21e8..000000000 --- a/build/runner/src/bundle/folder.rs +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright: Ankitects Pty Ltd and contributors -// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html - -use std::env; -use std::fs; -use std::process::Command; - -use camino::Utf8Path; -use camino::Utf8PathBuf; -use clap::Args; -use clap::ValueEnum; - -use crate::paths::absolute_msys_path; -use crate::paths::unix_path; -use crate::run::run_command; - -#[derive(Clone, Copy, ValueEnum, Debug)] -enum DistKind { - Standard, - Alternate, -} - -#[derive(Args, Debug)] -pub struct BuildDistFolderArgs { - kind: DistKind, - folder_root: Utf8PathBuf, -} - -pub fn build_dist_folder(args: BuildDistFolderArgs) { - let BuildDistFolderArgs { kind, folder_root } = args; - fs::create_dir_all(&folder_root).unwrap(); - // Start with Qt, as it's the largest, and we use --delete to ensure there are - // no stale files in lib/. Skipped on macOS as Qt is handled later. - if !cfg!(target_os = "macos") { - copy_qt_from_venv(kind, &folder_root); - } - clean_top_level_files(&folder_root); - copy_binary_and_pylibs(&folder_root); - if cfg!(target_os = "linux") { - copy_linux_extras(kind, &folder_root); - } else if cfg!(windows) { - copy_windows_extras(&folder_root); - } - fs::write(folder_root.with_extension("stamp"), b"").unwrap(); -} - -fn copy_qt_from_venv(kind: DistKind, folder_root: &Utf8Path) { - let python39 = if cfg!(windows) { "" } else { "python3.9/" }; - let qt_root = match kind { - DistKind::Standard => { - folder_root.join(format!("../pyenv/lib/{python39}site-packages/PyQt6")) - } - DistKind::Alternate => { - folder_root.join(format!("../pyenv-qt5/lib/{python39}site-packages/PyQt5")) - } - }; - let src_path = absolute_msys_path(&qt_root); - let lib_path = folder_root.join("lib"); - fs::create_dir_all(&lib_path).unwrap(); - let dst_path = with_slash(absolute_msys_path(&lib_path)); - run_command(Command::new("rsync").args([ - "-a", - "--delete", - "--exclude-from", - "qt/bundle/qt.exclude", - &src_path, - &dst_path, - ])); -} - -fn copy_linux_extras(kind: DistKind, folder_root: &Utf8Path) { - // add README, installer, etc - run_command(Command::new("rsync").args(["-a", "qt/bundle/lin/", &with_slash(folder_root)])); - - // add extra IME plugins from download - let lib_path = folder_root.join("lib"); - let src_path = folder_root - .join("../../extracted/linux_qt_plugins") - .join(match kind { - DistKind::Standard => "qt6", - DistKind::Alternate => "qt5", - }); - let dst_path = lib_path.join(match kind { - DistKind::Standard => "PyQt6/Qt6/plugins", - DistKind::Alternate => "PyQt5/Qt5/plugins", - }); - run_command(Command::new("rsync").args(["-a", &with_slash(src_path), &with_slash(dst_path)])); -} - -fn copy_windows_extras(folder_root: &Utf8Path) { - run_command(Command::new("rsync").args([ - "-a", - "out/extracted/win_amd64_audio/", - &with_slash(folder_root), - ])); -} - -fn clean_top_level_files(folder_root: &Utf8Path) { - let mut to_remove = vec![]; - for entry in fs::read_dir(folder_root).unwrap() { - let entry = entry.unwrap(); - if entry.file_name() == "lib" { - continue; - } else { - to_remove.push(entry.path()); - } - } - for path in to_remove { - if path.is_dir() { - fs::remove_dir_all(path).unwrap() - } else { - fs::remove_file(path).unwrap() - } - } -} - -fn with_slash

(path: P) -> String -where - P: AsRef, -{ - format!("{}/", path.as_ref()) -} - -fn copy_binary_and_pylibs(folder_root: &Utf8Path) { - let binary = folder_root - .join("../rust") - .join(env!("TARGET")) - .join("release") - .join(if cfg!(windows) { "anki.exe" } else { "anki" }); - let extra_files = folder_root - .join("../build") - .join(env!("TARGET")) - .join("release/resources/extra_files"); - run_command(Command::new("rsync").args([ - "-a", - "--exclude", - "PyQt6", - // misleading, as it misses the GPL PyQt, and our Rust/JS - // dependencies - "--exclude", - "COPYING.txt", - &unix_path(&binary), - &with_slash(unix_path(&extra_files)), - &with_slash(unix_path(folder_root)), - ])); - let google_py = if cfg!(windows) { - folder_root.join("../pyenv/lib/site-packages/google") - } else { - folder_root.join("../pyenv/lib/python3.9/site-packages/google") - }; - run_command(Command::new("rsync").args([ - "-a", - &unix_path(&google_py), - &with_slash(unix_path(&folder_root.join("lib"))), - ])); -} diff --git a/build/runner/src/bundle/mod.rs b/build/runner/src/bundle/mod.rs deleted file mode 100644 index 30a3608ab..000000000 --- a/build/runner/src/bundle/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright: Ankitects Pty Ltd and contributors -// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html - -pub mod artifacts; -pub mod binary; -pub mod folder; diff --git a/build/runner/src/main.rs b/build/runner/src/main.rs index 8fdf8f06f..41cc1fa2e 100644 --- a/build/runner/src/main.rs +++ b/build/runner/src/main.rs @@ -7,7 +7,6 @@ mod archive; mod build; -mod bundle; mod paths; mod pyenv; mod rsync; @@ -19,11 +18,6 @@ use archive::archive_command; use archive::ArchiveArgs; use build::run_build; use build::BuildArgs; -use bundle::artifacts::build_artifacts; -use bundle::artifacts::BuildArtifactsArgs; -use bundle::binary::build_bundle_binary; -use bundle::folder::build_dist_folder; -use bundle::folder::BuildDistFolderArgs; use clap::Parser; use clap::Subcommand; use pyenv::setup_pyenv; @@ -48,9 +42,6 @@ enum Command { Rsync(RsyncArgs), Run(RunArgs), Build(BuildArgs), - BuildArtifacts(BuildArtifactsArgs), - BuildBundleBinary, - BuildDistFolder(BuildDistFolderArgs), #[clap(subcommand)] Archive(ArchiveArgs), } @@ -62,9 +53,6 @@ fn main() -> Result<()> { Command::Rsync(args) => rsync_files(args), Command::Yarn(args) => setup_yarn(args), Command::Build(args) => run_build(args), - Command::BuildArtifacts(args) => build_artifacts(args), - Command::BuildBundleBinary => build_bundle_binary(), - Command::BuildDistFolder(args) => build_dist_folder(args), Command::Archive(args) => archive_command(args)?, }; Ok(()) diff --git a/build/runner/src/paths.rs b/build/runner/src/paths.rs index 2021120cb..c28dde1b9 100644 --- a/build/runner/src/paths.rs +++ b/build/runner/src/paths.rs @@ -16,8 +16,3 @@ pub fn absolute_msys_path(path: &Utf8Path) -> String { // and \ -> / format!("/{drive}/{}", path[7..].replace('\\', "/")) } - -/// Converts backslashes to forward slashes -pub fn unix_path(path: &Utf8Path) -> String { - path.as_str().replace('\\', "/") -} diff --git a/qt/bundle/build-mac-launcher.sh b/qt/bundle/build-mac-launcher.sh deleted file mode 100755 index d5ef9dcd4..000000000 --- a/qt/bundle/build-mac-launcher.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/bash - -set -e - -# Define output path -OUTPUT_DIR="../../out/bundle" -APP_BUNDLE="$OUTPUT_DIR/Anki.app" - -# Build rust binary in debug mode -cargo build -p launcher -(cd ../.. && ./ninja bundle:uv_universal) - -# Ensure output directory exists -mkdir -p "$OUTPUT_DIR" - -# Remove existing app bundle -rm -rf "$APP_BUNDLE" - -# Create app bundle structure -mkdir -p "$APP_BUNDLE/Contents/MacOS" "$APP_BUNDLE/Contents/Resources" - -# Copy binaries -TARGET_DIR=${CARGO_TARGET_DIR:-target} -cp $TARGET_DIR/debug/launcher "$APP_BUNDLE/Contents/MacOS/" -cp "$OUTPUT_DIR/uv" "$APP_BUNDLE/Contents/MacOS/" - -# Copy support files -cp launcher/Info.plist "$APP_BUNDLE/Contents/" -cp launcher/pyproject.toml "$APP_BUNDLE/Contents/Resources/" - -# Codesign -for i in "$APP_BUNDLE/Contents/MacOS/uv" "$APP_BUNDLE/Contents/MacOS/launcher" "$APP_BUNDLE"; do - codesign --force -vvvv -o runtime -s "Developer ID Application:" \ - --entitlements $c/desktop/anki/qt/bundle/mac/entitlements.python.xml \ - "$i" -done - -# Check -codesign -vvv "$APP_BUNDLE" -spctl -a "$APP_BUNDLE" - -# Mark as quarantined -#xattr -w com.apple.quarantine "0181;$(date +%s);Safari;" "$APP_BUNDLE" - diff --git a/qt/bundle/mac/Cargo.toml b/qt/bundle/mac/Cargo.toml deleted file mode 100644 index a154b76f7..000000000 --- a/qt/bundle/mac/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "makeapp" -version.workspace = true -authors.workspace = true -edition.workspace = true -license.workspace = true -publish = false -rust-version.workspace = true - -[dependencies] -anyhow.workspace = true -apple-bundles.workspace = true -camino.workspace = true -clap.workspace = true -glob.workspace = true -plist.workspace = true -serde.workspace = true -serde_json.workspace = true -simple-file-manifest.workspace = true -walkdir.workspace = true diff --git a/qt/bundle/mac/src/Info.plist b/qt/bundle/mac/src/Info.plist deleted file mode 100644 index e69de29bb..000000000 diff --git a/qt/bundle/mac/src/codesign.rs b/qt/bundle/mac/src/codesign.rs deleted file mode 100644 index fb251521f..000000000 --- a/qt/bundle/mac/src/codesign.rs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright: Ankitects Pty Ltd and contributors -// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html - -use std::env; -use std::process::Command; - -use anyhow::bail; -use anyhow::Result; -use camino::Utf8Path; -use camino::Utf8PathBuf; - -const CODESIGN_ARGS: &[&str] = &["-vvvv", "-o", "runtime", "-s", "Developer ID Application:"]; - -pub fn codesign_python_libs(bundle_dir: &Utf8PathBuf) -> Result<()> { - for entry in glob::glob(bundle_dir.join("Contents/MacOS/lib/**/*.so").as_str())? { - let entry = entry?; - let entry = Utf8PathBuf::from_path_buf(entry).unwrap(); - codesign_file(&entry, &[])?; - } - codesign_file(&bundle_dir.join("Contents/MacOS/libankihelper.dylib"), &[]) -} - -pub fn codesign_app(bundle_dir: &Utf8PathBuf) -> Result<()> { - codesign_file( - bundle_dir, - &["--entitlements", "qt/bundle/mac/entitlements.python.xml"], - ) -} - -fn codesign_file(path: &Utf8Path, extra_args: &[&str]) -> Result<()> { - if env::var("ANKI_CODESIGN").is_ok() { - let status = Command::new("codesign") - .args(CODESIGN_ARGS) - .args(extra_args) - .arg(path.as_str()) - .status()?; - if !status.success() { - bail!("codesign failed"); - } - } - - Ok(()) -} diff --git a/qt/bundle/mac/src/dmg.rs b/qt/bundle/mac/src/dmg.rs deleted file mode 100644 index 862150340..000000000 --- a/qt/bundle/mac/src/dmg.rs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright: Ankitects Pty Ltd and contributors -// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html - -use std::fs; -use std::process::Command; - -use anyhow::Context; -use anyhow::Result; -use camino::Utf8Path; -use camino::Utf8PathBuf; -use clap::Args; - -use crate::notarize::wait_then_staple_app; - -#[derive(Args)] -pub struct BuildDmgsArgs { - qt6_dmg: Utf8PathBuf, - qt5_dmg: Option, -} - -pub fn make_dmgs(args: BuildDmgsArgs) -> Result<()> { - let root = Utf8Path::new("out/bundle/app"); - let mut variants = vec![("std", args.qt6_dmg)]; - if let Some(alt) = args.qt5_dmg { - variants.push(("alt", alt)); - } - - for (variant, dmg) in variants { - let app = root.join(variant).join("Anki.app"); - if std::env::var("ANKI_CODESIGN").is_ok() { - let uuid = fs::read_to_string(app.with_extension("uuid")).context("read uuid")?; - wait_then_staple_app(&app, uuid)?; - } - - make_dmg(&app, &dmg)?; - } - - Ok(()) -} - -fn make_dmg(app_folder: &Utf8Path, dmg: &Utf8Path) -> Result<()> { - assert!( - Command::new("qt/bundle/mac/dmg/build.sh") - .args([app_folder.parent().unwrap().as_str(), dmg.as_str()]) - .status() - .context("dmg")? - .success(), - "dmg" - ); - Ok(()) -} diff --git a/qt/bundle/mac/src/main.rs b/qt/bundle/mac/src/main.rs deleted file mode 100644 index 2182d808e..000000000 --- a/qt/bundle/mac/src/main.rs +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright: Ankitects Pty Ltd and contributors -// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html - -#![cfg(unix)] - -//! Munge the output of PyOxidizer into a macOS app bundle, and combine it -//! with our other runtime dependencies. - -mod codesign; -mod dmg; -mod notarize; - -use std::env; -use std::fs; -use std::os::unix::prelude::PermissionsExt; -use std::process::Command; - -use anyhow::bail; -use anyhow::Result; -use apple_bundles::MacOsApplicationBundleBuilder; -use camino::Utf8Path; -use camino::Utf8PathBuf; -use clap::Parser; -use clap::Subcommand; -use clap::ValueEnum; -use codesign::codesign_app; -use codesign::codesign_python_libs; -use dmg::make_dmgs; -use dmg::BuildDmgsArgs; -use notarize::notarize_app; -use plist::Value; -use simple_file_manifest::FileEntry; -use walkdir::WalkDir; - -#[derive(Clone, ValueEnum)] -enum DistKind { - Standard, - Alternate, -} - -impl DistKind { - fn folder_name(&self) -> &'static str { - match self { - DistKind::Standard => "std", - DistKind::Alternate => "alt", - } - } - - fn input_folder(&self) -> Utf8PathBuf { - Utf8Path::new("out/bundle").join(self.folder_name()) - } - - fn output_folder(&self) -> Utf8PathBuf { - Utf8Path::new("out/bundle/app") - .join(self.folder_name()) - .join("Anki.app") - } - - fn macos_min(&self) -> &str { - match self { - DistKind::Standard => { - if env::var("MAC_X86").is_ok() { - "11" - } else { - "12" - } - } - DistKind::Alternate => "10.13.4", - } - } - - fn qt_repo(&self) -> &Utf8Path { - Utf8Path::new(match self { - DistKind::Standard => { - if cfg!(target_arch = "aarch64") && env::var("MAC_X86").is_err() { - "out/extracted/mac_arm_qt6" - } else { - "out/extracted/mac_amd_qt6" - } - } - DistKind::Alternate => "out/extracted/mac_amd_qt5", - }) - } -} - -#[derive(Parser)] -struct Cli { - #[command(subcommand)] - command: Commands, -} - -#[derive(Subcommand)] -enum Commands { - BuildApp { - version: String, - kind: DistKind, - stamp: Utf8PathBuf, - }, - BuildDmgs(BuildDmgsArgs), -} - -fn main() -> Result<()> { - match Cli::parse().command { - Commands::BuildApp { - version, - kind, - stamp, - } => { - let plist = get_plist(&version); - make_app(kind, plist, &stamp) - } - Commands::BuildDmgs(args) => make_dmgs(args), - } -} - -fn make_app(kind: DistKind, mut plist: plist::Dictionary, stamp: &Utf8Path) -> Result<()> { - let input_folder = kind.input_folder(); - let output_folder = kind.output_folder(); - let output_variant = output_folder.parent().unwrap(); - if output_variant.exists() { - fs::remove_dir_all(output_variant)?; - } - fs::create_dir_all(&output_folder)?; - - let mut builder = MacOsApplicationBundleBuilder::new("Anki")?; - plist.insert( - "LSMinimumSystemVersion".into(), - Value::from(kind.macos_min()), - ); - builder.set_info_plist_from_dictionary(plist)?; - builder.add_file_resources("Assets.car", &include_bytes!("../icon/Assets.car")[..])?; - - for entry in WalkDir::new(&input_folder) - .into_iter() - .map(Result::unwrap) - .filter(|e| !e.file_type().is_dir()) - { - let path = entry.path(); - let entry = FileEntry::try_from(path)?; - let relative_path = path.strip_prefix(&input_folder)?; - 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") - || path_str.contains("certifi") - || path_str.contains("google/protobuf") - { - builder.add_file_resources(relative_path.strip_prefix("lib").unwrap(), entry)?; - } else { - if path_str.contains("__pycache__") { - continue; - } - builder.add_file_macos(relative_path, entry)?; - } - } - - builder.files().materialize_files(&output_folder)?; - fix_rpath(output_folder.join("Contents/MacOS/anki"))?; - codesign_python_libs(&output_folder)?; - copy_in_audio(&output_folder)?; - copy_in_qt(&output_folder, kind)?; - codesign_app(&output_folder)?; - fixup_perms(&output_folder)?; - notarize_app(&output_folder)?; - fs::write(stamp, b"")?; - - Ok(()) -} - -/// The bundle builder writes some files without world read/execute perms, -/// which prevents them from being opened by a non-admin user. -fn fixup_perms(dir: &Utf8Path) -> Result<()> { - let status = Command::new("find") - .arg(dir) - .args(["-not", "-perm", "-a=r", "-exec", "chmod", "a+r", "{}", ";"]) - .status()?; - if !status.success() { - bail!("error setting perms"); - } - fs::set_permissions( - dir.join("Contents/MacOS/anki"), - PermissionsExt::from_mode(0o755), - )?; - Ok(()) -} - -/// Copy everything at the provided path into the Contents/ folder of our app. -fn extend_app_contents(source: &Utf8Path, target_dir: &Utf8Path) -> Result<()> { - let status = Command::new("rsync") - .arg("-a") - .arg(format!("{}/", source.as_str())) - .arg(target_dir) - .status()?; - if !status.success() { - bail!("error syncing {source:?}"); - } - Ok(()) -} - -fn copy_in_audio(bundle_dir: &Utf8Path) -> Result<()> { - println!("Copying in audio..."); - - let src_folder = Utf8Path::new( - if cfg!(target_arch = "aarch64") && env::var("MAC_X86").is_err() { - "out/extracted/mac_arm_audio" - } else { - "out/extracted/mac_amd_audio" - }, - ); - extend_app_contents(src_folder, &bundle_dir.join("Contents/Resources")) -} - -fn copy_in_qt(bundle_dir: &Utf8Path, kind: DistKind) -> Result<()> { - println!("Copying in Qt..."); - extend_app_contents(kind.qt_repo(), &bundle_dir.join("Contents")) -} - -fn fix_rpath(exe_path: Utf8PathBuf) -> Result<()> { - let status = Command::new("install_name_tool") - .arg("-add_rpath") - .arg("@executable_path/../Frameworks") - .arg(exe_path.as_str()) - .status()?; - assert!(status.success()); - Ok(()) -} - -fn get_plist(anki_version: &str) -> plist::Dictionary { - let reader = std::io::Cursor::new(include_bytes!("Info.plist")); - let mut plist = Value::from_reader(reader) - .unwrap() - .into_dictionary() - .unwrap(); - plist.insert( - "CFBundleShortVersionString".into(), - Value::from(anki_version), - ); - plist -} diff --git a/qt/bundle/mac/src/notarize.rs b/qt/bundle/mac/src/notarize.rs deleted file mode 100644 index 0688354f9..000000000 --- a/qt/bundle/mac/src/notarize.rs +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright: Ankitects Pty Ltd and contributors -// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html - -use std::env; -use std::fs; -use std::process::Command; - -use anyhow::bail; -use anyhow::Context; -use anyhow::Result; -use camino::Utf8Path; -use serde::Deserialize; - -#[derive(Deserialize)] -struct NotarySubmitOutput { - id: String, -} - -pub fn notarize_app(output_folder: &Utf8Path) -> Result<()> { - if env::var("ANKI_CODESIGN").is_err() { - return Ok(()); - } - if env::var("ANKI_NO_NOTARIZE").is_ok() { - return Ok(()); - } - let zip_file = output_folder.with_extension("zip"); - assert!( - Command::new("ditto") - .args([ - "-c", - "-k", - "--keepParent", - output_folder.as_str(), - zip_file.as_str(), - ]) - .status() - .unwrap() - .success(), - "zip build" - ); - let output = Command::new("xcrun") - .args([ - "notarytool", - "submit", - zip_file.as_str(), - "-f", - "json", - "-p", - "default", - ]) - .output() - .expect("notarytool"); - if !output.status.success() { - panic!( - "notarytool submit failed: {} {}", - String::from_utf8_lossy(&output.stderr), - String::from_utf8_lossy(&output.stdout) - ) - } - let output: NotarySubmitOutput = match serde_json::from_slice(&output.stdout) { - Ok(out) => out, - Err(err) => panic!( - "unable to parse notary output: {err} {} {}", - String::from_utf8_lossy(&output.stdout), - String::from_utf8_lossy(&output.stderr) - ), - }; - let uuid_path = output_folder.with_extension("uuid"); - fs::write(uuid_path, output.id).expect("write uuid"); - Ok(()) -} - -#[derive(Deserialize)] -struct NotaryWaitOutput { - status: String, -} - -pub fn wait_then_staple_app(app: &Utf8Path, uuid: String) -> Result<()> { - let output = Command::new("xcrun") - .args(["notarytool", "wait", &uuid, "-p", "default", "-f", "json"]) - .output() - .context("notary wait")?; - let output: NotaryWaitOutput = serde_json::from_slice(&output.stdout) - .with_context(|| String::from_utf8_lossy(&output.stderr).to_string())?; - if output.status != "Accepted" { - bail!("unexpected status: {}", output.status); - } - - assert!( - Command::new("xcrun") - .args(["stapler", "staple", app.as_str()]) - .status() - .context("staple")? - .success(), - "staple" - ); - - // clean up temporary files - fs::remove_file(app.with_extension("zip")).context("app.zip")?; - fs::remove_file(app.with_extension("uuid")).context("app.uuid")?; - - Ok(()) -} diff --git a/qt/bundle/win/Cargo.toml b/qt/bundle/win/Cargo.toml deleted file mode 100644 index 9c091b55f..000000000 --- a/qt/bundle/win/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "makeexe" -version.workspace = true -authors.workspace = true -edition.workspace = true -license.workspace = true -publish = false -rust-version.workspace = true - -[dependencies] -anyhow.workspace = true -camino.workspace = true -clap.workspace = true -tugger-windows-codesign.workspace = true -walkdir.workspace = true diff --git a/qt/bundle/win/src/main.rs b/qt/bundle/win/src/main.rs deleted file mode 100644 index 2091f6a51..000000000 --- a/qt/bundle/win/src/main.rs +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright: Ankitects Pty Ltd and contributors -// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html - -use std::fs; -use std::io::prelude::*; -use std::path::Path; -use std::process::Command; - -use anyhow::bail; -use anyhow::Context; -use anyhow::Result; -use camino::Utf8Path; -use camino::Utf8PathBuf; -use clap::Parser; -use tugger_windows_codesign::CodeSigningCertificate; -use tugger_windows_codesign::SigntoolSign; -use tugger_windows_codesign::SystemStore; -use tugger_windows_codesign::TimestampServer; -use walkdir::WalkDir; - -#[derive(Parser)] -struct Args { - version: String, - bundle_root: Utf8PathBuf, - qt6_setup_path: Utf8PathBuf, -} - -fn main() -> Result<()> { - let args = Args::parse(); - - let src_win_folder = Utf8Path::new("qt/bundle/win"); - let std_dist_folder = args.bundle_root.join("std"); - // folder->installer - let dists = [(&std_dist_folder, &args.qt6_setup_path)]; - - for (folder, _) in dists { - fs::copy( - src_win_folder.join("anki-console.bat"), - folder.join("anki-console.bat"), - ) - .context("anki-console")?; - } - - println!("--- Build uninstaller"); - build_installer( - &args.bundle_root, - &std_dist_folder, - &args.qt6_setup_path, - &args.version, - true, - ) - .context("uninstaller")?; - - // sign the anki.exe and uninstaller.exe in std - println!("--- Sign binaries"); - codesign([ - &std_dist_folder.join("anki.exe"), - &std_dist_folder.join("uninstall.exe"), - ])?; - - println!("--- Build manifest"); - for (folder, _) in dists { - build_manifest(folder).context("manifest")?; - } - - for (folder, installer) in dists { - println!("--- Build {}", installer); - build_installer(&args.bundle_root, folder, installer, &args.version, false)?; - } - - println!("--- Sign installers"); - codesign(dists.iter().map(|tup| tup.1))?; - - Ok(()) -} - -fn build_installer( - bundle_root: &Utf8Path, - dist_folder: &Utf8Path, - installer: &Utf8Path, - version: &str, - uninstaller: bool, -) -> Result<()> { - let rendered_nsi = include_str!("../anki.template.nsi") - .replace("@@SRC@@", dist_folder.as_str()) - .replace("@@INSTALLER@@", installer.as_str()) - .replace("@@VERSION@@", version); - let rendered_nsi_path = bundle_root.join("anki.nsi"); - fs::write(&rendered_nsi_path, rendered_nsi).context("anki.nsi")?; - fs::write( - bundle_root.join("fileassoc.nsh"), - include_str!("../fileassoc.nsh"), - )?; - fs::copy( - "out/extracted/nsis_plugins/nsProcess.dll", - bundle_root.join("nsProcess.dll"), - )?; - let mut cmd = Command::new("c:/program files (x86)/nsis/makensis.exe"); - cmd.arg("-V3"); - if uninstaller { - cmd.arg("-DWRITE_UNINSTALLER"); - }; - if option_env!("RELEASE").is_none() { - cmd.arg("-DNO_COMPRESS"); - } - cmd.arg(rendered_nsi_path); - let status = cmd.status()?; - if !status.success() { - bail!("makensis failed"); - } - Ok(()) -} - -fn codesign(paths: impl IntoIterator>) -> Result<()> { - if option_env!("ANKI_CODESIGN").is_none() { - return Ok(()); - } - let cert = CodeSigningCertificate::Sha1Thumbprint( - SystemStore::My, - "dccfc6d312fc0432197bb7be951478e5866eebf8".into(), - ); - let mut sign = SigntoolSign::new(cert); - sign.file_digest_algorithm("sha256") - .timestamp_server(TimestampServer::Rfc3161( - "http://time.certum.pl".into(), - "sha256".into(), - )) - .verbose(); - paths.into_iter().for_each(|path| { - sign.sign_file(path); - }); - sign.run() -} - -fn build_manifest(base_path: &Utf8Path) -> Result<()> { - let mut buf = vec![]; - for entry in WalkDir::new(base_path) - .min_depth(1) - .sort_by_file_name() - .into_iter() - { - let entry = entry?; - let path = entry.path(); - let relative_path = path.strip_prefix(base_path)?; - write!( - &mut buf, - "{}\r\n", - relative_path.to_str().context("relative_path utf8")? - )?; - } - fs::write(base_path.join("anki.install-manifest"), buf)?; - Ok(()) -} diff --git a/qt/bundle/.gitignore b/qt/launcher/.gitignore similarity index 100% rename from qt/bundle/.gitignore rename to qt/launcher/.gitignore diff --git a/qt/bundle/launcher/Cargo.toml b/qt/launcher/Cargo.toml similarity index 100% rename from qt/bundle/launcher/Cargo.toml rename to qt/launcher/Cargo.toml diff --git a/qt/bundle/lin/README.md b/qt/launcher/lin/README.md similarity index 100% rename from qt/bundle/lin/README.md rename to qt/launcher/lin/README.md diff --git a/qt/bundle/lin/anki.1 b/qt/launcher/lin/anki.1 similarity index 100% rename from qt/bundle/lin/anki.1 rename to qt/launcher/lin/anki.1 diff --git a/qt/bundle/lin/anki.desktop b/qt/launcher/lin/anki.desktop similarity index 100% rename from qt/bundle/lin/anki.desktop rename to qt/launcher/lin/anki.desktop diff --git a/qt/bundle/lin/anki.png b/qt/launcher/lin/anki.png similarity index 100% rename from qt/bundle/lin/anki.png rename to qt/launcher/lin/anki.png diff --git a/qt/bundle/lin/anki.xml b/qt/launcher/lin/anki.xml similarity index 100% rename from qt/bundle/lin/anki.xml rename to qt/launcher/lin/anki.xml diff --git a/qt/bundle/lin/anki.xpm b/qt/launcher/lin/anki.xpm similarity index 100% rename from qt/bundle/lin/anki.xpm rename to qt/launcher/lin/anki.xpm diff --git a/qt/bundle/lin/install.sh b/qt/launcher/lin/install.sh similarity index 100% rename from qt/bundle/lin/install.sh rename to qt/launcher/lin/install.sh diff --git a/qt/bundle/lin/uninstall.sh b/qt/launcher/lin/uninstall.sh similarity index 100% rename from qt/bundle/lin/uninstall.sh rename to qt/launcher/lin/uninstall.sh diff --git a/qt/bundle/launcher/Info.plist b/qt/launcher/mac/Info.plist similarity index 100% rename from qt/bundle/launcher/Info.plist rename to qt/launcher/mac/Info.plist diff --git a/qt/launcher/mac/build.sh b/qt/launcher/mac/build.sh new file mode 100755 index 000000000..4f50f6c69 --- /dev/null +++ b/qt/launcher/mac/build.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +set -e + +# Define output path +OUTPUT_DIR="../../../out/launcher" +APP_LAUNCHER="$OUTPUT_DIR/Anki.app" + +# Build rust binary in debug mode +cargo build -p launcher +(cd ../../.. && ./ninja launcher:uv_universal) + +# Ensure output directory exists +mkdir -p "$OUTPUT_DIR" + +# Remove existing app launcher +rm -rf "$APP_LAUNCHER" + +# Create app launcher structure +mkdir -p "$APP_LAUNCHER/Contents/MacOS" "$APP_LAUNCHER/Contents/Resources" + +# Copy binaries +TARGET_DIR=${CARGO_TARGET_DIR:-target} +cp $TARGET_DIR/debug/launcher "$APP_LAUNCHER/Contents/MacOS/" +cp "$OUTPUT_DIR/uv" "$APP_LAUNCHER/Contents/MacOS/" + +# Copy support files +cp Info.plist "$APP_LAUNCHER/Contents/" +cp icon/Assets.car "$APP_LAUNCHER/Contents/Resources/" +cp ../pyproject.toml "$APP_LAUNCHER/Contents/Resources/" + +# Codesign +for i in "$APP_LAUNCHER/Contents/MacOS/uv" "$APP_LAUNCHER/Contents/MacOS/launcher" "$APP_LAUNCHER"; do + codesign --force -vvvv -o runtime -s "Developer ID Application:" \ + --entitlements entitlements.python.xml \ + "$i" +done + +# Check +codesign -vvv "$APP_LAUNCHER" +spctl -a "$APP_LAUNCHER" diff --git a/qt/bundle/mac/dmg/anki-logo-bg.png b/qt/launcher/mac/dmg/anki-logo-bg.png similarity index 100% rename from qt/bundle/mac/dmg/anki-logo-bg.png rename to qt/launcher/mac/dmg/anki-logo-bg.png diff --git a/qt/bundle/mac/dmg/build.sh b/qt/launcher/mac/dmg/build.sh similarity index 100% rename from qt/bundle/mac/dmg/build.sh rename to qt/launcher/mac/dmg/build.sh diff --git a/qt/bundle/mac/dmg/dmg_ds_store b/qt/launcher/mac/dmg/dmg_ds_store similarity index 100% rename from qt/bundle/mac/dmg/dmg_ds_store rename to qt/launcher/mac/dmg/dmg_ds_store diff --git a/qt/bundle/mac/dmg/set-dmg-settings.app/Contents/Info.plist b/qt/launcher/mac/dmg/set-dmg-settings.app/Contents/Info.plist similarity index 100% rename from qt/bundle/mac/dmg/set-dmg-settings.app/Contents/Info.plist rename to qt/launcher/mac/dmg/set-dmg-settings.app/Contents/Info.plist diff --git a/qt/bundle/mac/dmg/set-dmg-settings.app/Contents/MacOS/applet b/qt/launcher/mac/dmg/set-dmg-settings.app/Contents/MacOS/applet similarity index 100% rename from qt/bundle/mac/dmg/set-dmg-settings.app/Contents/MacOS/applet rename to qt/launcher/mac/dmg/set-dmg-settings.app/Contents/MacOS/applet diff --git a/qt/bundle/mac/dmg/set-dmg-settings.app/Contents/PkgInfo b/qt/launcher/mac/dmg/set-dmg-settings.app/Contents/PkgInfo similarity index 100% rename from qt/bundle/mac/dmg/set-dmg-settings.app/Contents/PkgInfo rename to qt/launcher/mac/dmg/set-dmg-settings.app/Contents/PkgInfo diff --git a/qt/bundle/mac/dmg/set-dmg-settings.app/Contents/Resources/Scripts/main.scpt b/qt/launcher/mac/dmg/set-dmg-settings.app/Contents/Resources/Scripts/main.scpt similarity index 100% rename from qt/bundle/mac/dmg/set-dmg-settings.app/Contents/Resources/Scripts/main.scpt rename to qt/launcher/mac/dmg/set-dmg-settings.app/Contents/Resources/Scripts/main.scpt diff --git a/qt/bundle/mac/dmg/set-dmg-settings.app/Contents/Resources/applet.icns b/qt/launcher/mac/dmg/set-dmg-settings.app/Contents/Resources/applet.icns similarity index 100% rename from qt/bundle/mac/dmg/set-dmg-settings.app/Contents/Resources/applet.icns rename to qt/launcher/mac/dmg/set-dmg-settings.app/Contents/Resources/applet.icns diff --git a/qt/bundle/mac/dmg/set-dmg-settings.app/Contents/Resources/applet.rsrc b/qt/launcher/mac/dmg/set-dmg-settings.app/Contents/Resources/applet.rsrc similarity index 100% rename from qt/bundle/mac/dmg/set-dmg-settings.app/Contents/Resources/applet.rsrc rename to qt/launcher/mac/dmg/set-dmg-settings.app/Contents/Resources/applet.rsrc diff --git a/qt/bundle/mac/dmg/set-dmg-settings.app/Contents/Resources/description.rtfd/TXT.rtf b/qt/launcher/mac/dmg/set-dmg-settings.app/Contents/Resources/description.rtfd/TXT.rtf similarity index 100% rename from qt/bundle/mac/dmg/set-dmg-settings.app/Contents/Resources/description.rtfd/TXT.rtf rename to qt/launcher/mac/dmg/set-dmg-settings.app/Contents/Resources/description.rtfd/TXT.rtf diff --git a/qt/bundle/mac/dmg/set-dmg-settings.app/Contents/_CodeSignature/CodeResources b/qt/launcher/mac/dmg/set-dmg-settings.app/Contents/_CodeSignature/CodeResources similarity index 100% rename from qt/bundle/mac/dmg/set-dmg-settings.app/Contents/_CodeSignature/CodeResources rename to qt/launcher/mac/dmg/set-dmg-settings.app/Contents/_CodeSignature/CodeResources diff --git a/qt/bundle/mac/dmg/set-dmg-settings.scpt b/qt/launcher/mac/dmg/set-dmg-settings.scpt similarity index 100% rename from qt/bundle/mac/dmg/set-dmg-settings.scpt rename to qt/launcher/mac/dmg/set-dmg-settings.scpt diff --git a/qt/bundle/mac/entitlements.python.xml b/qt/launcher/mac/entitlements.python.xml similarity index 100% rename from qt/bundle/mac/entitlements.python.xml rename to qt/launcher/mac/entitlements.python.xml diff --git a/qt/bundle/mac/icon/Assets.car b/qt/launcher/mac/icon/Assets.car similarity index 100% rename from qt/bundle/mac/icon/Assets.car rename to qt/launcher/mac/icon/Assets.car diff --git a/qt/bundle/mac/icon/Assets.xcassets/AppIcon.appiconset/Contents.json b/qt/launcher/mac/icon/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from qt/bundle/mac/icon/Assets.xcassets/AppIcon.appiconset/Contents.json rename to qt/launcher/mac/icon/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/qt/bundle/mac/icon/Assets.xcassets/AppIcon.appiconset/round-1024-512.png b/qt/launcher/mac/icon/Assets.xcassets/AppIcon.appiconset/round-1024-512.png similarity index 100% rename from qt/bundle/mac/icon/Assets.xcassets/AppIcon.appiconset/round-1024-512.png rename to qt/launcher/mac/icon/Assets.xcassets/AppIcon.appiconset/round-1024-512.png diff --git a/qt/bundle/mac/icon/Assets.xcassets/Contents.json b/qt/launcher/mac/icon/Assets.xcassets/Contents.json similarity index 100% rename from qt/bundle/mac/icon/Assets.xcassets/Contents.json rename to qt/launcher/mac/icon/Assets.xcassets/Contents.json diff --git a/qt/bundle/mac/icon/build.sh b/qt/launcher/mac/icon/build.sh similarity index 100% rename from qt/bundle/mac/icon/build.sh rename to qt/launcher/mac/icon/build.sh diff --git a/qt/bundle/publish-release.sh b/qt/launcher/publish-release.sh similarity index 100% rename from qt/bundle/publish-release.sh rename to qt/launcher/publish-release.sh diff --git a/qt/bundle/launcher/pyproject.toml b/qt/launcher/pyproject.toml similarity index 100% rename from qt/bundle/launcher/pyproject.toml rename to qt/launcher/pyproject.toml diff --git a/qt/bundle/launcher/src/main.rs b/qt/launcher/src/main.rs similarity index 100% rename from qt/bundle/launcher/src/main.rs rename to qt/launcher/src/main.rs diff --git a/qt/bundle/update-release.sh b/qt/launcher/update-release.sh similarity index 100% rename from qt/bundle/update-release.sh rename to qt/launcher/update-release.sh diff --git a/qt/bundle/win/anki-console.bat b/qt/launcher/win/anki-console.bat similarity index 100% rename from qt/bundle/win/anki-console.bat rename to qt/launcher/win/anki-console.bat diff --git a/qt/bundle/win/anki-icon.ico b/qt/launcher/win/anki-icon.ico similarity index 100% rename from qt/bundle/win/anki-icon.ico rename to qt/launcher/win/anki-icon.ico diff --git a/qt/bundle/win/anki-manifest.rc b/qt/launcher/win/anki-manifest.rc similarity index 100% rename from qt/bundle/win/anki-manifest.rc rename to qt/launcher/win/anki-manifest.rc diff --git a/qt/bundle/win/anki.exe.manifest b/qt/launcher/win/anki.exe.manifest similarity index 100% rename from qt/bundle/win/anki.exe.manifest rename to qt/launcher/win/anki.exe.manifest diff --git a/qt/bundle/win/anki.template.nsi b/qt/launcher/win/anki.template.nsi similarity index 100% rename from qt/bundle/win/anki.template.nsi rename to qt/launcher/win/anki.template.nsi diff --git a/qt/bundle/win/fileassoc.nsh b/qt/launcher/win/fileassoc.nsh similarity index 100% rename from qt/bundle/win/fileassoc.nsh rename to qt/launcher/win/fileassoc.nsh diff --git a/tools/minilints/src/main.rs b/tools/minilints/src/main.rs index dfe9bef89..d5d6a4c7e 100644 --- a/tools/minilints/src/main.rs +++ b/tools/minilints/src/main.rs @@ -29,8 +29,6 @@ const NONSTANDARD_HEADER: &[&str] = &[ "./python/write_wheel.py", "./qt/aqt/mpv.py", "./qt/aqt/winpaths.py", - "./qt/bundle/build.rs", - "./qt/bundle/src/main.rs", ]; const IGNORED_FOLDERS: &[&str] = &[ @@ -38,7 +36,6 @@ const IGNORED_FOLDERS: &[&str] = &[ "./node_modules", "./qt/aqt/forms", "./tools/workspace-hack", - "./qt/bundle/PyOxidizer", "./target", ".mypy_cache", "./extra",