mirror of
https://github.com/tauri-apps/tauri.git
synced 2026-02-06 13:57:16 +00:00
Merge branch 'dev' into export-options-temp-file
This commit is contained in:
commit
d206b5df0e
5
.changes/android-external-files-fix.md
Normal file
5
.changes/android-external-files-fix.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"tauri": patch:bug
|
||||
---
|
||||
|
||||
Fixed 500 error when accessing local video files in Android external storage directory via `convertFileSrc`. Added better error handling and logging for Android external storage access to help diagnose permission and accessibility issues.
|
||||
6
.changes/change-pr-13253.md
Normal file
6
.changes/change-pr-13253.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
"@tauri-apps/cli": patch:enhance
|
||||
"tauri-cli": patch:enhance
|
||||
---
|
||||
|
||||
Allow electron to run the CLI directly
|
||||
5
.changes/change-pr-14766.md
Normal file
5
.changes/change-pr-14766.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"tauri-macos-sign": patch:deps
|
||||
---
|
||||
|
||||
Remove once-cell-regex from direct dependencies.
|
||||
6
.changes/empty-vec-instead-of-none.md
Normal file
6
.changes/empty-vec-instead-of-none.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
"@tauri-apps/cli": patch:enhance
|
||||
"tauri-cli": patch:enhance
|
||||
---
|
||||
|
||||
Simplified internal representation of `features: Option<Vec<String>>` with `Vec<String>`, no user facing changes
|
||||
6
.changes/fix-android-bundle-flag.md
Normal file
6
.changes/fix-android-bundle-flag.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
"tauri-cli": patch:bug
|
||||
"@tauri-apps/cli": patch:bug
|
||||
---
|
||||
|
||||
Fix `android build`'s `--aab` and `--apk` flags requiring a value to be provided.
|
||||
8
.changes/fix-binary-patching.md
Normal file
8
.changes/fix-binary-patching.md
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
"tauri": minor:changes
|
||||
"tauri-cli": minor:changes
|
||||
"tauri-bundler": minor:changes
|
||||
"@tauri-apps/cli": minor:changes
|
||||
---
|
||||
|
||||
Change the way bundle type information is added to binary files. Instead of looking up the value of a variable we simply look for the default value.
|
||||
6
.changes/fix-empty-entitlements.md
Normal file
6
.changes/fix-empty-entitlements.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
"tauri-cli": patch:bug
|
||||
"@tauri-apps/cli": patch:bug
|
||||
---
|
||||
|
||||
Fix empty associated-domains entitlements when domains are not configured for deep links.
|
||||
6
.changes/fix-inspect-description.md
Normal file
6
.changes/fix-inspect-description.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
"@tauri-apps/cli": patch:bug
|
||||
"tauri-cli": patch:bug
|
||||
---
|
||||
|
||||
Fixed the command description for `tauri inspect`
|
||||
6
.changes/only-watch-dependencies.md
Normal file
6
.changes/only-watch-dependencies.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
"@tauri-apps/cli": patch:bug
|
||||
"tauri-cli": patch:bug
|
||||
---
|
||||
|
||||
Only watch dependent workspace members when running `tauri dev` instead of watching on all members
|
||||
6
.changes/reduce-internal-statics.md
Normal file
6
.changes/reduce-internal-statics.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
"@tauri-apps/cli": patch:changes
|
||||
"tauri-cli": patch:changes
|
||||
---
|
||||
|
||||
Refactored internal use of static on config and directory resolvings, no user facing changes, please report any regressions if you encounter any
|
||||
6
.changes/runtime-bsd.md
Normal file
6
.changes/runtime-bsd.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
tauri-runtime: patch:bug
|
||||
tauri-runtime-wry: patch:bug
|
||||
---
|
||||
|
||||
Fix compilation errors when targeting BSD.
|
||||
14
.changes/signing-env-vars.md
Normal file
14
.changes/signing-env-vars.md
Normal file
@ -0,0 +1,14 @@
|
||||
---
|
||||
"tauri-cli": patch:enhance
|
||||
"@tauri-apps/cli": patch:enhance
|
||||
---
|
||||
|
||||
Added new environment variables for `tauri signer sign` command, to align with existing environment variables used in `tauri build`, `tauri bundle` and `tauri signer generate`
|
||||
- `TAURI_SIGNING_PRIVATE_KEY`
|
||||
- `TAURI_SIGNING_PRIVATE_KEY_PATH`
|
||||
- `TAURI_SIGNING_PRIVATE_KEY_PASSWORD`
|
||||
|
||||
The old environment variables are deprecated and will be removed in a future release.
|
||||
- `TAURI_PRIVATE_KEY`
|
||||
- `TAURI_PRIVATE_KEY_PATH`
|
||||
- `TAURI_PRIVATE_KEY_PASSWORD`
|
||||
6
.changes/updater-signer-files-without-extension.md
Normal file
6
.changes/updater-signer-files-without-extension.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
tauri-cli: patch:bug
|
||||
"@tauri-apps/cli": patch:bug
|
||||
---
|
||||
|
||||
`tauri signer sign` doesn't work for files without an extension
|
||||
7
.changes/webkitgtk202.md
Normal file
7
.changes/webkitgtk202.md
Normal file
@ -0,0 +1,7 @@
|
||||
---
|
||||
tauri-runtime-wry: minor:deps
|
||||
tauri-runtime: minor:deps
|
||||
tauri: minor:deps
|
||||
---
|
||||
|
||||
**Breaking Change** for `with_webview` users: Updated webkit2gtk-rs crates to `v2.0.2`.
|
||||
7
.changes/webview-set-simple-fullscreen.md
Normal file
7
.changes/webview-set-simple-fullscreen.md
Normal file
@ -0,0 +1,7 @@
|
||||
---
|
||||
'tauri': 'minor:feat'
|
||||
---
|
||||
|
||||
Add `set_simple_fullscreen` method to `WebviewWindow`.
|
||||
|
||||
This method was already available on the `Window` type and is now also available on `WebviewWindow` for consistency. On macOS, it toggles fullscreen mode without creating a new macOS Space. On other platforms, it falls back to regular fullscreen.
|
||||
6
.changes/wry-054.md
Normal file
6
.changes/wry-054.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
tauri-runtime-wry: patch:deps
|
||||
tauri: patch:deps
|
||||
---
|
||||
|
||||
Update wry to `v0.54`.
|
||||
29
.github/workflows/publish-cli-rs.yml
vendored
29
.github/workflows/publish-cli-rs.yml
vendored
@ -38,35 +38,62 @@ jobs:
|
||||
rust_target: aarch64-pc-windows-msvc
|
||||
ext: '.exe'
|
||||
args: ''
|
||||
- os: ubuntu-22.04
|
||||
rust_target: riscv64gc-unknown-linux-gnu
|
||||
ext: ''
|
||||
args: ''
|
||||
cross: true
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: 'Setup Rust'
|
||||
if: ${{ !matrix.config.cross }}
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: ${{ matrix.config.rust_target }}
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
if: ${{ !matrix.config.cross }}
|
||||
with:
|
||||
key: ${{ matrix.config.rust_target }}
|
||||
|
||||
- name: install Linux dependencies
|
||||
if: matrix.config.os == 'ubuntu-latest'
|
||||
if: ${{ !matrix.config.cross && startsWith(matrix.config.os, 'ubuntu') }}
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libgtk-3-dev
|
||||
|
||||
- name: Install cross
|
||||
if: ${{ matrix.config.cross }}
|
||||
uses: taiki-e/install-action@v2
|
||||
with:
|
||||
tool: cross@0.2.5
|
||||
|
||||
- name: Build CLI
|
||||
if: ${{ !matrix.config.cross }}
|
||||
run: cargo build --manifest-path ./crates/tauri-cli/Cargo.toml --profile release-size-optimized ${{ matrix.config.args }}
|
||||
|
||||
- name: Build CLI (cross)
|
||||
if: ${{ matrix.config.cross }}
|
||||
run: cross build --manifest-path ./crates/tauri-cli/Cargo.toml --target ${{ matrix.config.rust_target }} --profile release-size-optimized ${{ matrix.config.args }}
|
||||
|
||||
- name: Upload CLI
|
||||
if: ${{ !matrix.config.cross }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: cargo-tauri-${{ matrix.config.rust_target }}${{ matrix.config.ext }}
|
||||
path: target/release-size-optimized/cargo-tauri${{ matrix.config.ext }}
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload CLI (cross)
|
||||
if: ${{ matrix.config.cross }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: cargo-tauri-${{ matrix.config.rust_target }}${{ matrix.config.ext }}
|
||||
path: target/${{ matrix.config.rust_target }}/release-size-optimized/cargo-tauri${{ matrix.config.ext }}
|
||||
if-no-files-found: error
|
||||
|
||||
upload:
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
16
.taurignore
16
.taurignore
@ -1,16 +0,0 @@
|
||||
.changes
|
||||
.devcontainer
|
||||
.docker
|
||||
.github
|
||||
.scripts
|
||||
.vscode
|
||||
audits
|
||||
bench
|
||||
packages/api
|
||||
packages/cli
|
||||
crates/tauri-cli
|
||||
crates/tauri-bundler
|
||||
crates/tauri-driver
|
||||
crates/tauri-macos-sign
|
||||
crates/tauri-schema-generator
|
||||
crates/tests
|
||||
414
Cargo.lock
generated
414
Cargo.lock
generated
@ -300,7 +300,7 @@ dependencies = [
|
||||
"ring",
|
||||
"rsa",
|
||||
"scroll",
|
||||
"security-framework",
|
||||
"security-framework 2.11.1",
|
||||
"security-framework-sys",
|
||||
"semver",
|
||||
"serde",
|
||||
@ -567,7 +567,7 @@ dependencies = [
|
||||
"http 1.3.1",
|
||||
"http-body 1.0.1",
|
||||
"http-body-util",
|
||||
"hyper 1.5.2",
|
||||
"hyper 1.8.1",
|
||||
"hyper-util",
|
||||
"itoa",
|
||||
"matchit 0.8.4",
|
||||
@ -1152,10 +1152,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.22"
|
||||
version = "1.2.51"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32db95edf998450acc7881c932f94cd9b05c87b4b2599e8bab064753da4acfd1"
|
||||
checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203"
|
||||
dependencies = [
|
||||
"find-msvc-tools",
|
||||
"jobserver",
|
||||
"libc",
|
||||
"shlex",
|
||||
@ -2333,11 +2334,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "erased-serde"
|
||||
version = "0.4.5"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24e2389d65ab4fab27dc2a5de7b191e1f6617d1f1c8855c0dc569c94a4cbb18d"
|
||||
checksum = "89e8918065695684b2b0702da20382d5ae6065cf3327bc2d6436bd49a71ce9f3"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_core",
|
||||
"typeid",
|
||||
]
|
||||
|
||||
@ -2468,6 +2470,12 @@ dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "find-msvc-tools"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.1"
|
||||
@ -2853,10 +2861,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3347,7 +3353,7 @@ dependencies = [
|
||||
"httpdate",
|
||||
"itoa",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"socket2 0.5.8",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
@ -3356,13 +3362,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "1.5.2"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0"
|
||||
checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11"
|
||||
dependencies = [
|
||||
"atomic-waker",
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"futures-core",
|
||||
"h2 0.4.7",
|
||||
"http 1.3.1",
|
||||
"http-body 1.0.1",
|
||||
@ -3370,6 +3377,7 @@ dependencies = [
|
||||
"httpdate",
|
||||
"itoa",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"smallvec",
|
||||
"tokio",
|
||||
"want",
|
||||
@ -3397,14 +3405,13 @@ checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"http 1.3.1",
|
||||
"hyper 1.5.2",
|
||||
"hyper 1.8.1",
|
||||
"hyper-util",
|
||||
"rustls 0.23.20",
|
||||
"rustls 0.23.35",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
"tokio-rustls 0.26.1",
|
||||
"tower-service",
|
||||
"webpki-roots 0.26.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3415,7 +3422,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http-body-util",
|
||||
"hyper 1.5.2",
|
||||
"hyper 1.8.1",
|
||||
"hyper-util",
|
||||
"native-tls",
|
||||
"tokio",
|
||||
@ -3425,18 +3432,23 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hyper-util"
|
||||
version = "0.1.10"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4"
|
||||
checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"http 1.3.1",
|
||||
"http-body 1.0.1",
|
||||
"hyper 1.5.2",
|
||||
"hyper 1.8.1",
|
||||
"ipnet",
|
||||
"libc",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"socket2 0.6.1",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
@ -3817,6 +3829,16 @@ version = "2.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708"
|
||||
|
||||
[[package]]
|
||||
name = "iri-string"
|
||||
version = "0.7.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is-terminal"
|
||||
version = "0.4.13"
|
||||
@ -3916,20 +3938,6 @@ dependencies = [
|
||||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jni"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec"
|
||||
dependencies = [
|
||||
"cesu8",
|
||||
"combine",
|
||||
"jni-sys",
|
||||
"log",
|
||||
"thiserror 1.0.69",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jni"
|
||||
version = "0.21.1"
|
||||
@ -4077,7 +4085,7 @@ dependencies = [
|
||||
"http 1.3.1",
|
||||
"http-body 1.0.1",
|
||||
"http-body-util",
|
||||
"hyper 1.5.2",
|
||||
"hyper 1.8.1",
|
||||
"hyper-util",
|
||||
"jsonrpsee-core",
|
||||
"jsonrpsee-types",
|
||||
@ -4140,7 +4148,6 @@ dependencies = [
|
||||
"referencing",
|
||||
"regex",
|
||||
"regex-syntax",
|
||||
"reqwest 0.12.12",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"uuid-simd",
|
||||
@ -4289,9 +4296,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.169"
|
||||
version = "0.2.178"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
|
||||
checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
|
||||
|
||||
[[package]]
|
||||
name = "libfuzzer-sys"
|
||||
@ -4428,9 +4435,9 @@ checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.22"
|
||||
version = "0.4.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
||||
dependencies = [
|
||||
"value-bag",
|
||||
]
|
||||
@ -4720,10 +4727,10 @@ dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"openssl",
|
||||
"openssl-probe",
|
||||
"openssl-probe 0.1.5",
|
||||
"openssl-sys",
|
||||
"schannel",
|
||||
"security-framework",
|
||||
"security-framework 2.11.1",
|
||||
"security-framework-sys",
|
||||
"tempfile",
|
||||
]
|
||||
@ -5353,6 +5360,12 @@ version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-probe"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f50d9b3dabb09ecd771ad0aa242ca6894994c130308ca3d7684634df8037391"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-src"
|
||||
version = "300.4.1+3.4.0"
|
||||
@ -6356,58 +6369,6 @@ dependencies = [
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quinn"
|
||||
version = "0.11.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"pin-project-lite",
|
||||
"quinn-proto",
|
||||
"quinn-udp",
|
||||
"rustc-hash",
|
||||
"rustls 0.23.20",
|
||||
"socket2",
|
||||
"thiserror 2.0.12",
|
||||
"tokio",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quinn-proto"
|
||||
version = "0.11.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"getrandom 0.2.15",
|
||||
"rand 0.8.5",
|
||||
"ring",
|
||||
"rustc-hash",
|
||||
"rustls 0.23.20",
|
||||
"rustls-pki-types",
|
||||
"slab",
|
||||
"thiserror 2.0.12",
|
||||
"tinyvec",
|
||||
"tracing",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quinn-udp"
|
||||
version = "0.5.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c40286217b4ba3a71d644d752e6a0b71f13f1b6a2c5311acfcbe0c2418ed904"
|
||||
dependencies = [
|
||||
"cfg_aliases",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"socket2",
|
||||
"tracing",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.38"
|
||||
@ -6818,51 +6779,44 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.12.12"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da"
|
||||
checksum = "04e9018c9d814e5f30cc16a0f03271aeab3571e609612d9fe78c1aa8d11c2f62"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"http 1.3.1",
|
||||
"http-body 1.0.1",
|
||||
"http-body-util",
|
||||
"hyper 1.5.2",
|
||||
"hyper 1.8.1",
|
||||
"hyper-rustls 0.27.5",
|
||||
"hyper-tls",
|
||||
"hyper-util",
|
||||
"ipnet",
|
||||
"js-sys",
|
||||
"log",
|
||||
"mime",
|
||||
"native-tls",
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"quinn",
|
||||
"rustls 0.23.20",
|
||||
"rustls-pemfile 2.2.0",
|
||||
"rustls 0.23.35",
|
||||
"rustls-pki-types",
|
||||
"rustls-platform-verifier",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"sync_wrapper 1.0.2",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
"tokio-rustls 0.26.1",
|
||||
"tokio-util",
|
||||
"tower 0.5.2",
|
||||
"tower-http",
|
||||
"tower-service",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"wasm-streams",
|
||||
"web-sys",
|
||||
"webpki-roots 0.26.7",
|
||||
"windows-registry 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -6944,9 +6898,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rkyv"
|
||||
version = "0.7.45"
|
||||
version = "0.7.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b"
|
||||
checksum = "2297bf9c81a3f0dc96bc9521370b88f054168c29826a75e89c55ff196e7ed6a1"
|
||||
dependencies = [
|
||||
"bitvec",
|
||||
"bytecheck",
|
||||
@ -6962,9 +6916,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rkyv_derive"
|
||||
version = "0.7.45"
|
||||
version = "0.7.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0"
|
||||
checksum = "84d7b42d4b8d06048d3ac8db0eb31bcb942cbeb709f0b5f2b2ebde398d3038f5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -7026,9 +6980,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rsa"
|
||||
version = "0.9.7"
|
||||
version = "0.9.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47c75d7c5c6b673e58bf54d8544a9f432e3a925b0e80f7cd3602ab5c50c55519"
|
||||
checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d"
|
||||
dependencies = [
|
||||
"const-oid",
|
||||
"digest",
|
||||
@ -7168,15 +7122,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.23.20"
|
||||
version = "0.23.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b"
|
||||
checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f"
|
||||
dependencies = [
|
||||
"log",
|
||||
"once_cell",
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
"rustls-webpki 0.102.8",
|
||||
"rustls-webpki 0.103.8",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
@ -7187,10 +7141,10 @@ version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00"
|
||||
dependencies = [
|
||||
"openssl-probe",
|
||||
"openssl-probe 0.1.5",
|
||||
"rustls-pemfile 1.0.4",
|
||||
"schannel",
|
||||
"security-framework",
|
||||
"security-framework 2.11.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -7199,11 +7153,23 @@ version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5"
|
||||
dependencies = [
|
||||
"openssl-probe",
|
||||
"openssl-probe 0.1.5",
|
||||
"rustls-pemfile 2.2.0",
|
||||
"rustls-pki-types",
|
||||
"schannel",
|
||||
"security-framework",
|
||||
"security-framework 2.11.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-native-certs"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63"
|
||||
dependencies = [
|
||||
"openssl-probe 0.2.0",
|
||||
"rustls-pki-types",
|
||||
"schannel",
|
||||
"security-framework 3.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -7226,32 +7192,32 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pki-types"
|
||||
version = "1.10.1"
|
||||
version = "1.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37"
|
||||
checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282"
|
||||
dependencies = [
|
||||
"web-time",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-platform-verifier"
|
||||
version = "0.3.4"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afbb878bdfdf63a336a5e63561b1835e7a8c91524f51621db870169eac84b490"
|
||||
checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784"
|
||||
dependencies = [
|
||||
"core-foundation 0.9.4",
|
||||
"core-foundation 0.10.0",
|
||||
"core-foundation-sys",
|
||||
"jni 0.19.0",
|
||||
"jni",
|
||||
"log",
|
||||
"once_cell",
|
||||
"rustls 0.23.20",
|
||||
"rustls-native-certs 0.7.3",
|
||||
"rustls 0.23.35",
|
||||
"rustls-native-certs 0.8.3",
|
||||
"rustls-platform-verifier-android",
|
||||
"rustls-webpki 0.102.8",
|
||||
"security-framework",
|
||||
"rustls-webpki 0.103.8",
|
||||
"security-framework 3.5.1",
|
||||
"security-framework-sys",
|
||||
"webpki-roots 0.26.7",
|
||||
"winapi",
|
||||
"webpki-root-certs",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -7281,6 +7247,17 @@ dependencies = [
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.103.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.19"
|
||||
@ -7479,15 +7456,27 @@ dependencies = [
|
||||
"core-foundation 0.9.4",
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
"num-bigint",
|
||||
"security-framework-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
version = "3.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef"
|
||||
dependencies = [
|
||||
"bitflags 2.7.0",
|
||||
"core-foundation 0.10.0",
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
"security-framework-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "security-framework-sys"
|
||||
version = "2.14.0"
|
||||
version = "2.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32"
|
||||
checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
@ -7864,9 +7853,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.3.17"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801"
|
||||
checksum = "2a37d01603c37b5466f808de79f845c7116049b0579adb70a6b7d47c1fa3a952"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"signal-hook-registry",
|
||||
@ -7883,9 +7872,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-tokio"
|
||||
version = "0.3.1"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "213241f76fb1e37e27de3b6aa1b068a2c333233b59cca6634f634b80a27ecf1e"
|
||||
checksum = "e513e435a8898a0002270f29d0a708b7879708fb5c4d00e46983ca2d2d378cf0"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"libc",
|
||||
@ -8020,6 +8009,16 @@ dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socks"
|
||||
version = "0.3.4"
|
||||
@ -8446,7 +8445,7 @@ dependencies = [
|
||||
"gdkwayland-sys",
|
||||
"gdkx11-sys",
|
||||
"gtk",
|
||||
"jni 0.21.1",
|
||||
"jni",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
@ -8522,7 +8521,7 @@ dependencies = [
|
||||
"http 1.3.1",
|
||||
"http-range",
|
||||
"image",
|
||||
"jni 0.21.1",
|
||||
"jni",
|
||||
"libc",
|
||||
"log",
|
||||
"mime",
|
||||
@ -8538,7 +8537,8 @@ dependencies = [
|
||||
"quickcheck",
|
||||
"quickcheck_macros",
|
||||
"raw-window-handle",
|
||||
"reqwest 0.12.12",
|
||||
"reqwest 0.13.1",
|
||||
"rustls 0.23.35",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_repr",
|
||||
@ -8626,7 +8626,7 @@ dependencies = [
|
||||
"uuid",
|
||||
"walkdir",
|
||||
"which",
|
||||
"windows-registry 0.5.0",
|
||||
"windows-registry",
|
||||
"windows-sys 0.60.2",
|
||||
"zip 4.0.0",
|
||||
]
|
||||
@ -8758,7 +8758,7 @@ dependencies = [
|
||||
"futures",
|
||||
"futures-util",
|
||||
"http-body-util",
|
||||
"hyper 1.5.2",
|
||||
"hyper 1.8.1",
|
||||
"hyper-util",
|
||||
"pico-args",
|
||||
"serde",
|
||||
@ -8799,11 +8799,12 @@ dependencies = [
|
||||
"chrono",
|
||||
"dirs 6.0.0",
|
||||
"log",
|
||||
"once-cell-regex",
|
||||
"once_cell",
|
||||
"os_pipe",
|
||||
"p12",
|
||||
"plist",
|
||||
"rand 0.9.1",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tempfile",
|
||||
@ -8879,7 +8880,7 @@ dependencies = [
|
||||
"dpi",
|
||||
"gtk",
|
||||
"http 1.3.1",
|
||||
"jni 0.21.1",
|
||||
"jni",
|
||||
"objc2 0.6.0",
|
||||
"objc2-ui-kit",
|
||||
"objc2-web-kit",
|
||||
@ -8900,7 +8901,7 @@ version = "2.9.3"
|
||||
dependencies = [
|
||||
"gtk",
|
||||
"http 1.3.1",
|
||||
"jni 0.21.1",
|
||||
"jni",
|
||||
"log",
|
||||
"objc2 0.6.0",
|
||||
"objc2-app-kit",
|
||||
@ -8978,6 +8979,7 @@ dependencies = [
|
||||
"serial_test",
|
||||
"serialize-to-javascript",
|
||||
"swift-rs",
|
||||
"tauri",
|
||||
"thiserror 2.0.12",
|
||||
"toml 0.9.10+spec-1.1.0",
|
||||
"url",
|
||||
@ -9225,7 +9227,7 @@ dependencies = [
|
||||
"parking_lot",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2",
|
||||
"socket2 0.5.8",
|
||||
"tokio-macros",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
@ -9267,7 +9269,7 @@ version = "0.26.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37"
|
||||
dependencies = [
|
||||
"rustls 0.23.20",
|
||||
"rustls 0.23.35",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
@ -9450,6 +9452,24 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-http"
|
||||
version = "0.6.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8"
|
||||
dependencies = [
|
||||
"bitflags 2.7.0",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http 1.3.1",
|
||||
"http-body 1.0.1",
|
||||
"iri-string",
|
||||
"pin-project-lite",
|
||||
"tower 0.5.2",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-layer"
|
||||
version = "0.3.3"
|
||||
@ -9789,33 +9809,31 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||
|
||||
[[package]]
|
||||
name = "ureq"
|
||||
version = "3.0.3"
|
||||
version = "3.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "217751151c53226090391713e533d9a5e904ba2570dabaaace29032687589c3e"
|
||||
checksum = "d39cb1dbab692d82a977c0392ffac19e188bd9186a9f32806f0aaa859d75585a"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"cc",
|
||||
"der",
|
||||
"flate2",
|
||||
"log",
|
||||
"native-tls",
|
||||
"percent-encoding",
|
||||
"rustls 0.23.20",
|
||||
"rustls-pemfile 2.2.0",
|
||||
"rustls 0.23.35",
|
||||
"rustls-pki-types",
|
||||
"rustls-platform-verifier",
|
||||
"socks",
|
||||
"ureq-proto",
|
||||
"utf-8",
|
||||
"webpki-root-certs",
|
||||
"webpki-roots 0.26.7",
|
||||
"webpki-roots 1.0.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ureq-proto"
|
||||
version = "0.3.0"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c51fe73e1d8c4e06bb2698286f7e7453c6fc90528d6d2e7fc36bb4e87fe09b1"
|
||||
checksum = "d81f9efa9df032be5934a46a068815a10a042b494b6a58cb0a1a97bb5467ed6f"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"http 1.3.1",
|
||||
@ -9939,9 +9957,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "value-bag"
|
||||
version = "1.10.0"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ef4c4aa54d5d05a279399bfa921ec387b7aba77caf7a682ae8d86785b8fdad2"
|
||||
checksum = "7ba6f5989077681266825251a52748b8c1d8a4ad098cc37e440103d0ea717fc0"
|
||||
dependencies = [
|
||||
"value-bag-serde1",
|
||||
"value-bag-sval2",
|
||||
@ -9949,20 +9967,20 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "value-bag-serde1"
|
||||
version = "1.10.0"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bb773bd36fd59c7ca6e336c94454d9c66386416734817927ac93d81cb3c5b0b"
|
||||
checksum = "16530907bfe2999a1773ca5900a65101e092c70f642f25cc23ca0c43573262c5"
|
||||
dependencies = [
|
||||
"erased-serde",
|
||||
"serde",
|
||||
"serde_core",
|
||||
"serde_fmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "value-bag-sval2"
|
||||
version = "1.10.0"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53a916a702cac43a88694c97657d449775667bcd14b70419441d05b7fea4a83a"
|
||||
checksum = "d00ae130edd690eaa877e4f40605d534790d1cf1d651e7685bd6a144521b251f"
|
||||
dependencies = [
|
||||
"sval",
|
||||
"sval_buffer",
|
||||
@ -10153,21 +10171,11 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "web-time"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webkit2gtk"
|
||||
version = "2.0.1"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76b1bc1e54c581da1e9f179d0b38512ba358fb1af2d634a1affe42e37172361a"
|
||||
checksum = "a1027150013530fb2eaf806408df88461ae4815a45c541c8975e61d6f2fc4793"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"cairo-rs",
|
||||
@ -10189,9 +10197,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "webkit2gtk-sys"
|
||||
version = "2.0.1"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62daa38afc514d1f8f12b8693d30d5993ff77ced33ce30cd04deebc267a6d57c"
|
||||
checksum = "916a5f65c2ef0dfe12fff695960a2ec3d4565359fdbb2e9943c974e06c734ea5"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"cairo-sys-rs",
|
||||
@ -10209,9 +10217,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "webpki-root-certs"
|
||||
version = "0.26.7"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9cd5da49bdf1f30054cfe0b8ce2958b8fbeb67c4d82c8967a598af481bef255c"
|
||||
checksum = "36a29fc0408b113f68cf32637857ab740edfafdf460c326cd2afaa2d84cc05dc"
|
||||
dependencies = [
|
||||
"rustls-pki-types",
|
||||
]
|
||||
@ -10224,9 +10232,9 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1"
|
||||
|
||||
[[package]]
|
||||
name = "webpki-roots"
|
||||
version = "0.26.7"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e"
|
||||
checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c"
|
||||
dependencies = [
|
||||
"rustls-pki-types",
|
||||
]
|
||||
@ -10396,7 +10404,7 @@ dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-link",
|
||||
"windows-result 0.3.2",
|
||||
"windows-result",
|
||||
"windows-strings 0.4.0",
|
||||
]
|
||||
|
||||
@ -10448,17 +10456,6 @@ dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-registry"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0"
|
||||
dependencies = [
|
||||
"windows-result 0.2.0",
|
||||
"windows-strings 0.1.0",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-registry"
|
||||
version = "0.5.0"
|
||||
@ -10466,19 +10463,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c44a98275e31bfd112bb06ba96c8ab13c03383a3753fdddd715406a1824c7e0"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
"windows-result 0.3.2",
|
||||
"windows-result",
|
||||
"windows-strings 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.3.2"
|
||||
@ -10488,16 +10476,6 @@ dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
|
||||
dependencies = [
|
||||
"windows-result 0.2.0",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.3.1"
|
||||
@ -10938,9 +10916,9 @@ checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
|
||||
|
||||
[[package]]
|
||||
name = "wry"
|
||||
version = "0.53.4"
|
||||
version = "0.54.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d78ec082b80fa088569a970d043bb3050abaabf4454101d44514ee8d9a8c9f6"
|
||||
checksum = "e456eeaf7f09413fdc16799782879b2b9f1d264dfdbce4cf7e924df0ef36afb9"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"block2 0.6.0",
|
||||
@ -10954,7 +10932,7 @@ dependencies = [
|
||||
"html5ever",
|
||||
"http 1.3.1",
|
||||
"javascriptcore-rs",
|
||||
"jni 0.21.1",
|
||||
"jni",
|
||||
"kuchikiki",
|
||||
"libc",
|
||||
"ndk",
|
||||
|
||||
@ -4,6 +4,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
mod category;
|
||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
||||
mod kmp;
|
||||
#[cfg(target_os = "linux")]
|
||||
mod linux;
|
||||
#[cfg(target_os = "macos")]
|
||||
@ -15,29 +17,46 @@ mod windows;
|
||||
|
||||
use tauri_utils::{display_path, platform::Target as TargetPlatform};
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
||||
const BUNDLE_VAR_TOKEN: &[u8] = b"__TAURI_BUNDLE_TYPE_VAR_UNK";
|
||||
/// Patch a binary with bundle type information
|
||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
||||
fn patch_binary(binary: &PathBuf, package_type: &PackageType) -> crate::Result<()> {
|
||||
match package_type {
|
||||
#[cfg(target_os = "linux")]
|
||||
PackageType::AppImage | PackageType::Deb | PackageType::Rpm => {
|
||||
log::info!(
|
||||
"Patching binary {:?} for type {}",
|
||||
binary,
|
||||
package_type.short_name()
|
||||
);
|
||||
linux::patch_binary(binary, package_type)?;
|
||||
}
|
||||
PackageType::Nsis | PackageType::WindowsMsi => {
|
||||
log::info!(
|
||||
"Patching binary {:?} for type {}",
|
||||
binary,
|
||||
package_type.short_name()
|
||||
);
|
||||
windows::patch_binary(binary, package_type)?;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
let mut file_data = std::fs::read(binary).expect("Could not read binary file.");
|
||||
|
||||
if let Some(bundle_var_index) = kmp::index_of(BUNDLE_VAR_TOKEN, &file_data) {
|
||||
#[cfg(target_os = "linux")]
|
||||
let bundle_type = match package_type {
|
||||
crate::PackageType::Deb => b"__TAURI_BUNDLE_TYPE_VAR_DEB",
|
||||
crate::PackageType::Rpm => b"__TAURI_BUNDLE_TYPE_VAR_RPM",
|
||||
crate::PackageType::AppImage => b"__TAURI_BUNDLE_TYPE_VAR_APP",
|
||||
_ => {
|
||||
return Err(crate::Error::InvalidPackageType(
|
||||
package_type.short_name().to_owned(),
|
||||
"Linux".to_owned(),
|
||||
))
|
||||
}
|
||||
};
|
||||
#[cfg(target_os = "windows")]
|
||||
let bundle_type = match package_type {
|
||||
crate::PackageType::Nsis => b"__TAURI_BUNDLE_TYPE_VAR_NSS",
|
||||
crate::PackageType::WindowsMsi => b"__TAURI_BUNDLE_TYPE_VAR_MSI",
|
||||
_ => {
|
||||
return Err(crate::Error::InvalidPackageType(
|
||||
package_type.short_name().to_owned(),
|
||||
"Windows".to_owned(),
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
file_data[bundle_var_index..bundle_var_index + BUNDLE_VAR_TOKEN.len()]
|
||||
.copy_from_slice(bundle_type);
|
||||
|
||||
std::fs::write(binary, &file_data)
|
||||
.map_err(|e| crate::Error::BinaryWriteError(e.to_string()))?;
|
||||
} else {
|
||||
return Err(crate::Error::MissingBundleTypeVar);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -92,22 +111,17 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<Bundle>> {
|
||||
.expect("Main binary missing in settings");
|
||||
let main_binary_path = settings.binary_path(main_binary);
|
||||
|
||||
// When packaging multiple binary types, we make a copy of the unsigned main_binary so that we can
|
||||
// restore it after each package_type step. This avoids two issues:
|
||||
// We make a copy of the unsigned main_binary so that we can restore it after each package_type step.
|
||||
// This allows us to patch the binary correctly and avoids two issues:
|
||||
// - modifying a signed binary without updating its PE checksum can break signature verification
|
||||
// - codesigning tools should handle calculating+updating this, we just need to ensure
|
||||
// (re)signing is performed after every `patch_binary()` operation
|
||||
// - signing an already-signed binary can result in multiple signatures, causing verification errors
|
||||
let main_binary_reset_required = matches!(target_os, TargetPlatform::Windows)
|
||||
&& settings.windows().can_sign()
|
||||
&& package_types.len() > 1;
|
||||
let mut unsigned_main_binary_copy = tempfile::tempfile()?;
|
||||
if main_binary_reset_required {
|
||||
let mut unsigned_main_binary = std::fs::File::open(&main_binary_path)?;
|
||||
std::io::copy(&mut unsigned_main_binary, &mut unsigned_main_binary_copy)?;
|
||||
}
|
||||
// TODO: change this to work on a copy while preserving the main binary unchanged
|
||||
let mut main_binary_copy = tempfile::tempfile()?;
|
||||
let mut main_binary_orignal = std::fs::File::open(&main_binary_path)?;
|
||||
std::io::copy(&mut main_binary_orignal, &mut main_binary_copy)?;
|
||||
|
||||
let mut main_binary_signed = false;
|
||||
let mut bundles = Vec::<Bundle>::new();
|
||||
for package_type in &package_types {
|
||||
// bundle was already built! e.g. DMG already built .app
|
||||
@ -115,22 +129,14 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<Bundle>> {
|
||||
continue;
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
||||
if let Err(e) = patch_binary(&main_binary_path, package_type) {
|
||||
log::warn!("Failed to add bundler type to the binary: {e}. Updater plugin may not be able to update this package. This shouldn't normally happen, please report it to https://github.com/tauri-apps/tauri/issues");
|
||||
}
|
||||
|
||||
// sign main binary for every package type after patch
|
||||
if matches!(target_os, TargetPlatform::Windows) && settings.windows().can_sign() {
|
||||
if main_binary_signed && main_binary_reset_required {
|
||||
let mut signed_main_binary = std::fs::OpenOptions::new()
|
||||
.write(true)
|
||||
.truncate(true)
|
||||
.open(&main_binary_path)?;
|
||||
unsigned_main_binary_copy.seek(SeekFrom::Start(0))?;
|
||||
std::io::copy(&mut unsigned_main_binary_copy, &mut signed_main_binary)?;
|
||||
}
|
||||
windows::sign::try_sign(&main_binary_path, settings)?;
|
||||
main_binary_signed = true;
|
||||
}
|
||||
|
||||
let bundle_paths = match package_type {
|
||||
@ -172,6 +178,14 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<Bundle>> {
|
||||
package_type: package_type.to_owned(),
|
||||
bundle_paths,
|
||||
});
|
||||
|
||||
// Restore unsigned and unpatched binary
|
||||
let mut modified_main_binary = std::fs::OpenOptions::new()
|
||||
.write(true)
|
||||
.truncate(true)
|
||||
.open(&main_binary_path)?;
|
||||
main_binary_copy.seek(SeekFrom::Start(0))?;
|
||||
std::io::copy(&mut main_binary_copy, &mut modified_main_binary)?;
|
||||
}
|
||||
|
||||
if let Some(updater) = settings.updater() {
|
||||
|
||||
61
crates/tauri-bundler/src/bundle/kmp/mod.rs
Normal file
61
crates/tauri-bundler/src/bundle/kmp/mod.rs
Normal file
@ -0,0 +1,61 @@
|
||||
// Copyright 2016-2019 Cargo-Bundle developers <https://github.com/burtonageo/cargo-bundle>
|
||||
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// Knuth–Morris–Pratt algorithm
|
||||
// based on https://github.com/howeih/rust_kmp
|
||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
||||
pub fn index_of(pattern: &[u8], target: &[u8]) -> Option<usize> {
|
||||
let failure_function = find_failure_function(pattern);
|
||||
|
||||
let mut t_i: usize = 0;
|
||||
let mut p_i: usize = 0;
|
||||
let target_len = target.len();
|
||||
let mut result_idx = None;
|
||||
let pattern_len = pattern.len();
|
||||
|
||||
while (t_i < target_len) && (p_i < pattern_len) {
|
||||
if target[t_i] == pattern[p_i] {
|
||||
if result_idx.is_none() {
|
||||
result_idx.replace(t_i);
|
||||
}
|
||||
t_i += 1;
|
||||
p_i += 1;
|
||||
if p_i >= pattern_len {
|
||||
return result_idx;
|
||||
}
|
||||
} else {
|
||||
if p_i == 0 {
|
||||
p_i = 0;
|
||||
t_i += 1;
|
||||
} else {
|
||||
p_i = failure_function[p_i - 1];
|
||||
}
|
||||
result_idx = None;
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
||||
fn find_failure_function(pattern: &[u8]) -> Vec<usize> {
|
||||
let mut i = 1;
|
||||
let mut j = 0;
|
||||
let pattern_length = pattern.len();
|
||||
let end_i = pattern_length - 1;
|
||||
let mut failure_function = vec![0usize; pattern_length];
|
||||
while i <= end_i {
|
||||
if pattern[i] == pattern[j] {
|
||||
failure_function[i] = j + 1;
|
||||
i += 1;
|
||||
j += 1;
|
||||
} else if j == 0 {
|
||||
failure_function[i] = 0;
|
||||
i += 1;
|
||||
} else {
|
||||
j = failure_function[j - 1];
|
||||
}
|
||||
}
|
||||
failure_function
|
||||
}
|
||||
@ -7,8 +7,3 @@ pub mod appimage;
|
||||
pub mod debian;
|
||||
pub mod freedesktop;
|
||||
pub mod rpm;
|
||||
|
||||
mod util;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub use util::patch_binary;
|
||||
|
||||
@ -1,59 +0,0 @@
|
||||
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/// Change value of __TAURI_BUNDLE_TYPE static variable to mark which package type it was bundled in
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn patch_binary(
|
||||
binary_path: &std::path::PathBuf,
|
||||
package_type: &crate::PackageType,
|
||||
) -> crate::Result<()> {
|
||||
let mut file_data = std::fs::read(binary_path).expect("Could not read binary file.");
|
||||
|
||||
let elf = match goblin::Object::parse(&file_data)? {
|
||||
goblin::Object::Elf(elf) => elf,
|
||||
_ => return Err(crate::Error::GenericError("Not an ELF file".to_owned())),
|
||||
};
|
||||
|
||||
let offset = find_bundle_type_symbol(elf).ok_or(crate::Error::MissingBundleTypeVar)?;
|
||||
let offset = offset as usize;
|
||||
if offset + 3 <= file_data.len() {
|
||||
let chars = &mut file_data[offset..offset + 3];
|
||||
match package_type {
|
||||
crate::PackageType::Deb => chars.copy_from_slice(b"DEB"),
|
||||
crate::PackageType::Rpm => chars.copy_from_slice(b"RPM"),
|
||||
crate::PackageType::AppImage => chars.copy_from_slice(b"APP"),
|
||||
_ => {
|
||||
return Err(crate::Error::InvalidPackageType(
|
||||
package_type.short_name().to_owned(),
|
||||
"linux".to_owned(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
std::fs::write(binary_path, &file_data)
|
||||
.map_err(|error| crate::Error::BinaryWriteError(error.to_string()))?;
|
||||
} else {
|
||||
return Err(crate::Error::BinaryOffsetOutOfRange);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Find address of a symbol in relocations table
|
||||
#[cfg(target_os = "linux")]
|
||||
fn find_bundle_type_symbol(elf: goblin::elf::Elf<'_>) -> Option<i64> {
|
||||
for sym in elf.syms.iter() {
|
||||
if let Some(name) = elf.strtab.get_at(sym.st_name) {
|
||||
if name == "__TAURI_BUNDLE_TYPE" {
|
||||
for reloc in elf.dynrelas.iter() {
|
||||
if reloc.r_offset == sym.st_value {
|
||||
return Some(reloc.r_addend.unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
@ -21,7 +21,7 @@ pub fn keychain(identity: Option<&str>) -> crate::Result<Option<tauri_macos_sign
|
||||
var_os("APPLE_CERTIFICATE"),
|
||||
var_os("APPLE_CERTIFICATE_PASSWORD"),
|
||||
) {
|
||||
// import user certificate - useful for for CI build
|
||||
// import user certificate - useful for CI build
|
||||
let keychain =
|
||||
tauri_macos_sign::Keychain::with_certificate(&certificate_encoded, &certificate_password)
|
||||
.map_err(Box::new)?;
|
||||
|
||||
@ -231,7 +231,7 @@ pub struct AppImageSettings {
|
||||
pub struct RpmSettings {
|
||||
/// The list of RPM dependencies your application relies on.
|
||||
pub depends: Option<Vec<String>>,
|
||||
/// the list of of RPM dependencies your application recommends.
|
||||
/// the list of RPM dependencies your application recommends.
|
||||
pub recommends: Option<Vec<String>>,
|
||||
/// The list of RPM dependencies your application provides.
|
||||
pub provides: Option<Vec<String>>,
|
||||
|
||||
@ -14,5 +14,3 @@ pub use util::{
|
||||
NSIS_OUTPUT_FOLDER_NAME, NSIS_UPDATER_OUTPUT_FOLDER_NAME, WIX_OUTPUT_FOLDER_NAME,
|
||||
WIX_UPDATER_OUTPUT_FOLDER_NAME,
|
||||
};
|
||||
|
||||
pub use util::patch_binary;
|
||||
|
||||
@ -77,75 +77,3 @@ pub fn os_bitness<'a>() -> Option<&'a str> {
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn patch_binary(binary_path: &PathBuf, package_type: &crate::PackageType) -> crate::Result<()> {
|
||||
let mut file_data = std::fs::read(binary_path)?;
|
||||
|
||||
let pe = match goblin::Object::parse(&file_data)? {
|
||||
goblin::Object::PE(pe) => pe,
|
||||
_ => {
|
||||
return Err(crate::Error::BinaryParseError(
|
||||
std::io::Error::new(std::io::ErrorKind::InvalidInput, "binary is not a PE file").into(),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
let tauri_bundle_section = pe
|
||||
.sections
|
||||
.iter()
|
||||
.find(|s| s.name().unwrap_or_default() == ".taubndl")
|
||||
.ok_or(crate::Error::MissingBundleTypeVar)?;
|
||||
|
||||
let data_offset = tauri_bundle_section.pointer_to_raw_data as usize;
|
||||
let pointer_size = if pe.is_64 { 8 } else { 4 };
|
||||
let ptr_bytes = file_data
|
||||
.get(data_offset..data_offset + pointer_size)
|
||||
.ok_or(crate::Error::BinaryOffsetOutOfRange)?;
|
||||
// `try_into` is safe to `unwrap` here because we have already checked the slice's size through `get`
|
||||
let ptr_value = if pe.is_64 {
|
||||
u64::from_le_bytes(ptr_bytes.try_into().unwrap())
|
||||
} else {
|
||||
u32::from_le_bytes(ptr_bytes.try_into().unwrap()).into()
|
||||
};
|
||||
|
||||
let rdata_section = pe
|
||||
.sections
|
||||
.iter()
|
||||
.find(|s| s.name().unwrap_or_default() == ".rdata")
|
||||
.ok_or_else(|| {
|
||||
crate::Error::BinaryParseError(
|
||||
std::io::Error::new(std::io::ErrorKind::InvalidInput, ".rdata section not found").into(),
|
||||
)
|
||||
})?;
|
||||
|
||||
let rva = ptr_value.checked_sub(pe.image_base as u64).ok_or_else(|| {
|
||||
crate::Error::BinaryParseError(
|
||||
std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid RVA offset").into(),
|
||||
)
|
||||
})?;
|
||||
|
||||
// see "Relative virtual address (RVA)" for explanation of offset arithmetic here:
|
||||
// https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#general-concepts
|
||||
let file_offset = rdata_section.pointer_to_raw_data as usize
|
||||
+ (rva as usize).saturating_sub(rdata_section.virtual_address as usize);
|
||||
|
||||
// Overwrite the string at that offset
|
||||
let string_bytes = file_data
|
||||
.get_mut(file_offset..file_offset + 3)
|
||||
.ok_or(crate::Error::BinaryOffsetOutOfRange)?;
|
||||
match package_type {
|
||||
crate::PackageType::Nsis => string_bytes.copy_from_slice(b"NSS"),
|
||||
crate::PackageType::WindowsMsi => string_bytes.copy_from_slice(b"MSI"),
|
||||
_ => {
|
||||
return Err(crate::Error::InvalidPackageType(
|
||||
package_type.short_name().to_owned(),
|
||||
"windows".to_owned(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
std::fs::write(binary_path, &file_data)
|
||||
.map_err(|e| crate::Error::BinaryWriteError(e.to_string()))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -99,19 +99,13 @@ pub enum Error {
|
||||
#[error("Wrong package type {0} for platform {1}")]
|
||||
InvalidPackageType(String, String),
|
||||
/// Bundle type symbol missing in binary
|
||||
#[cfg_attr(
|
||||
target_os = "linux",
|
||||
error("__TAURI_BUNDLE_TYPE variable not found in binary. Make sure tauri crate and tauri-cli are up to date and that symbol stripping is disabled (https://doc.rust-lang.org/cargo/reference/profiles.html#strip)")
|
||||
)]
|
||||
#[cfg_attr(
|
||||
not(target_os = "linux"),
|
||||
error("__TAURI_BUNDLE_TYPE variable not found in binary. Make sure tauri crate and tauri-cli are up to date")
|
||||
)]
|
||||
#[error("__TAURI_BUNDLE_TYPE variable not found in binary. Make sure tauri crate and tauri-cli are up to date")]
|
||||
MissingBundleTypeVar,
|
||||
/// Failed to write binary file changed
|
||||
#[error("Failed to write binary file changes: `{0}`")]
|
||||
BinaryWriteError(String),
|
||||
/// Invalid offset while patching binary file
|
||||
#[deprecated]
|
||||
#[error("Invalid offset while patching binary file")]
|
||||
BinaryOffsetOutOfRange,
|
||||
/// Unsupported architecture.
|
||||
|
||||
@ -66,7 +66,7 @@ tauri-utils = { version = "2.8.1", path = "../tauri-utils", features = [
|
||||
"html-manipulation",
|
||||
] }
|
||||
toml = "0.9"
|
||||
jsonschema = "0.33"
|
||||
jsonschema = { version = "0.33", default-features = false }
|
||||
handlebars = "6"
|
||||
include_dir = "0.7"
|
||||
dirs = "6"
|
||||
|
||||
@ -165,7 +165,7 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"windows": {
|
||||
"description": "The app windows configuration.\n\n ## Example:\n\n To create a window at app startup\n\n ```json\n {\n \"app\": {\n \"windows\": [\n { \"width\": 800, \"height\": 600 }\n ]\n }\n }\n ```\n\n If not specified, the window's label (its identifier) defaults to \"main\",\n you can use this label to get the window through\n `app.get_webview_window` in Rust or `WebviewWindow.getByLabel` in JavaScript\n\n When working with multiple windows, each window will need an unique label\n\n ```json\n {\n \"app\": {\n \"windows\": [\n { \"label\": \"main\", \"width\": 800, \"height\": 600 },\n { \"label\": \"secondary\", \"width\": 800, \"height\": 600 }\n ]\n }\n }\n ```\n\n You can also set `create` to false and use this config through the Rust APIs\n\n ```json\n {\n \"app\": {\n \"windows\": [\n { \"create\": false, \"width\": 800, \"height\": 600 }\n ]\n }\n }\n ```\n\n and use it like this\n\n ```rust\n tauri::Builder::default()\n .setup(|app| {\n tauri::WebviewWindowBuilder::from_config(app.handle(), app.config().app.windows[0])?.build()?;\n Ok(())\n });\n ```",
|
||||
"description": "The app windows configuration.\n\n ## Example:\n\n To create a window at app startup\n\n ```json\n {\n \"app\": {\n \"windows\": [\n { \"width\": 800, \"height\": 600 }\n ]\n }\n }\n ```\n\n If not specified, the window's label (its identifier) defaults to \"main\",\n you can use this label to get the window through\n `app.get_webview_window` in Rust or `WebviewWindow.getByLabel` in JavaScript\n\n When working with multiple windows, each window will need an unique label\n\n ```json\n {\n \"app\": {\n \"windows\": [\n { \"label\": \"main\", \"width\": 800, \"height\": 600 },\n { \"label\": \"secondary\", \"width\": 800, \"height\": 600 }\n ]\n }\n }\n ```\n\n You can also set `create` to false and use this config through the Rust APIs\n\n ```json\n {\n \"app\": {\n \"windows\": [\n { \"create\": false, \"width\": 800, \"height\": 600 }\n ]\n }\n }\n ```\n\n and use it like this\n\n ```rust\n tauri::Builder::default()\n .setup(|app| {\n tauri::WebviewWindowBuilder::from_config(app.handle(), &app.config().app.windows[0])?.build()?;\n Ok(())\n });\n ```",
|
||||
"default": [],
|
||||
"type": "array",
|
||||
"items": {
|
||||
|
||||
@ -7,12 +7,7 @@ use std::{collections::HashSet, path::PathBuf};
|
||||
use clap::Parser;
|
||||
use tauri_utils::acl::capability::{Capability, PermissionEntry};
|
||||
|
||||
use crate::{
|
||||
acl::FileFormat,
|
||||
error::ErrorExt,
|
||||
helpers::{app_paths::tauri_dir, prompts},
|
||||
Result,
|
||||
};
|
||||
use crate::{acl::FileFormat, error::ErrorExt, helpers::prompts, Result};
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[clap(about = "Create a new permission file")]
|
||||
@ -37,7 +32,7 @@ pub struct Options {
|
||||
}
|
||||
|
||||
pub fn command(options: Options) -> Result<()> {
|
||||
crate::helpers::app_paths::resolve();
|
||||
let dirs = crate::helpers::app_paths::resolve_dirs();
|
||||
|
||||
let identifier = match options.identifier {
|
||||
Some(i) => i,
|
||||
@ -111,8 +106,7 @@ pub fn command(options: Options) -> Result<()> {
|
||||
.canonicalize()
|
||||
.fs_context("failed to canonicalize capability file path", o.clone())?,
|
||||
None => {
|
||||
let dir = tauri_dir();
|
||||
let capabilities_dir = dir.join("capabilities");
|
||||
let capabilities_dir = dirs.tauri.join("capabilities");
|
||||
capabilities_dir.join(format!(
|
||||
"{}.{}",
|
||||
capability.identifier,
|
||||
|
||||
@ -6,7 +6,6 @@ use clap::Parser;
|
||||
|
||||
use crate::{
|
||||
error::{Context, ErrorExt},
|
||||
helpers::app_paths::tauri_dir,
|
||||
Result,
|
||||
};
|
||||
use colored::Colorize;
|
||||
@ -25,9 +24,10 @@ pub struct Options {
|
||||
}
|
||||
|
||||
pub fn command(options: Options) -> Result<()> {
|
||||
crate::helpers::app_paths::resolve();
|
||||
let dirs = crate::helpers::app_paths::resolve_dirs();
|
||||
|
||||
let acl_manifests_path = tauri_dir()
|
||||
let acl_manifests_path = dirs
|
||||
.tauri
|
||||
.join("gen")
|
||||
.join("schemas")
|
||||
.join("acl-manifests.json");
|
||||
|
||||
@ -10,7 +10,7 @@ use crate::{
|
||||
acl,
|
||||
error::ErrorExt,
|
||||
helpers::{
|
||||
app_paths::{resolve_frontend_dir, tauri_dir},
|
||||
app_paths::{resolve_frontend_dir, Dirs},
|
||||
cargo,
|
||||
npm::PackageManager,
|
||||
},
|
||||
@ -39,11 +39,11 @@ pub struct Options {
|
||||
}
|
||||
|
||||
pub fn command(options: Options) -> Result<()> {
|
||||
crate::helpers::app_paths::resolve();
|
||||
run(options)
|
||||
let dirs = crate::helpers::app_paths::resolve_dirs();
|
||||
run(options, &dirs)
|
||||
}
|
||||
|
||||
pub fn run(options: Options) -> Result<()> {
|
||||
pub fn run(options: Options, dirs: &Dirs) -> Result<()> {
|
||||
let (plugin, version) = options
|
||||
.plugin
|
||||
.split_once('@')
|
||||
@ -71,7 +71,6 @@ pub fn run(options: Options) -> Result<()> {
|
||||
}
|
||||
|
||||
let frontend_dir = resolve_frontend_dir();
|
||||
let tauri_dir = tauri_dir();
|
||||
|
||||
let target_str = metadata
|
||||
.desktop_only
|
||||
@ -90,7 +89,7 @@ pub fn run(options: Options) -> Result<()> {
|
||||
branch: options.branch.as_deref(),
|
||||
rev: options.rev.as_deref(),
|
||||
tag: options.tag.as_deref(),
|
||||
cwd: Some(tauri_dir),
|
||||
cwd: Some(dirs.tauri),
|
||||
target: target_str,
|
||||
})?;
|
||||
|
||||
@ -117,7 +116,7 @@ pub fn run(options: Options) -> Result<()> {
|
||||
(None, None, None, None) => npm_name,
|
||||
_ => crate::error::bail!("Only one of --tag, --rev and --branch can be specified"),
|
||||
};
|
||||
manager.install(&[npm_spec], tauri_dir)?;
|
||||
manager.install(&[npm_spec], dirs.tauri)?;
|
||||
}
|
||||
|
||||
let _ = acl::permission::add::command(acl::permission::add::Options {
|
||||
@ -143,7 +142,10 @@ pub fn run(options: Options) -> Result<()> {
|
||||
let plugin_init = format!(".plugin(tauri_plugin_{plugin_snake_case}::{plugin_init_fn})");
|
||||
|
||||
let re = Regex::new(r"(tauri\s*::\s*Builder\s*::\s*default\(\))(\s*)").unwrap();
|
||||
for file in [tauri_dir.join("src/main.rs"), tauri_dir.join("src/lib.rs")] {
|
||||
for file in [
|
||||
dirs.tauri.join("src/main.rs"),
|
||||
dirs.tauri.join("src/lib.rs"),
|
||||
] {
|
||||
let contents =
|
||||
std::fs::read_to_string(&file).fs_context("failed to read Rust entry point", file.clone())?;
|
||||
|
||||
@ -166,7 +168,7 @@ pub fn run(options: Options) -> Result<()> {
|
||||
log::info!("Running `cargo fmt`...");
|
||||
let _ = Command::new("cargo")
|
||||
.arg("fmt")
|
||||
.current_dir(tauri_dir)
|
||||
.current_dir(dirs.tauri)
|
||||
.status();
|
||||
}
|
||||
|
||||
|
||||
@ -7,8 +7,8 @@ use crate::{
|
||||
error::{Context, ErrorExt},
|
||||
helpers::{
|
||||
self,
|
||||
app_paths::{frontend_dir, tauri_dir},
|
||||
config::{get as get_config, ConfigMetadata, FrontendDist},
|
||||
app_paths::Dirs,
|
||||
config::{get_config, ConfigMetadata, FrontendDist},
|
||||
},
|
||||
info::plugins::check_mismatched_packages,
|
||||
interface::{rust::get_cargo_target_dir, AppInterface, Interface},
|
||||
@ -40,7 +40,7 @@ pub struct Options {
|
||||
pub target: Option<String>,
|
||||
/// Space or comma separated list of features to activate
|
||||
#[clap(short, long, action = ArgAction::Append, num_args(0..))]
|
||||
pub features: Option<Vec<String>>,
|
||||
pub features: Vec<String>,
|
||||
/// Space or comma separated list of bundles to package.
|
||||
#[clap(short, long, action = ArgAction::Append, num_args(0..), value_delimiter = ',')]
|
||||
pub bundles: Option<Vec<BundleFormat>>,
|
||||
@ -82,7 +82,7 @@ pub struct Options {
|
||||
}
|
||||
|
||||
pub fn command(mut options: Options, verbosity: u8) -> Result<()> {
|
||||
crate::helpers::app_paths::resolve();
|
||||
let dirs = crate::helpers::app_paths::resolve_dirs();
|
||||
|
||||
if options.no_sign {
|
||||
log::warn!("--no-sign flag detected: Signing will be skipped.");
|
||||
@ -99,41 +99,37 @@ pub fn command(mut options: Options, verbosity: u8) -> Result<()> {
|
||||
let config = get_config(
|
||||
target,
|
||||
&options.config.iter().map(|c| &c.0).collect::<Vec<_>>(),
|
||||
dirs.tauri,
|
||||
)?;
|
||||
|
||||
let mut interface = AppInterface::new(
|
||||
config.lock().unwrap().as_ref().unwrap(),
|
||||
options.target.clone(),
|
||||
)?;
|
||||
let mut interface = AppInterface::new(&config, options.target.clone(), dirs.tauri)?;
|
||||
|
||||
let config_guard = config.lock().unwrap();
|
||||
let config_ = config_guard.as_ref().unwrap();
|
||||
setup(&interface, &mut options, &config, &dirs, false)?;
|
||||
|
||||
setup(&interface, &mut options, config_, false)?;
|
||||
|
||||
if let Some(minimum_system_version) = &config_.bundle.macos.minimum_system_version {
|
||||
if let Some(minimum_system_version) = &config.bundle.macos.minimum_system_version {
|
||||
std::env::set_var("MACOSX_DEPLOYMENT_TARGET", minimum_system_version);
|
||||
}
|
||||
|
||||
let app_settings = interface.app_settings();
|
||||
let interface_options = options.clone().into();
|
||||
|
||||
let out_dir = app_settings.out_dir(&interface_options)?;
|
||||
let out_dir = app_settings.out_dir(&interface_options, dirs.tauri)?;
|
||||
|
||||
let bin_path = interface.build(interface_options)?;
|
||||
let bin_path = interface.build(interface_options, &dirs)?;
|
||||
|
||||
log::info!(action ="Built"; "application at: {}", tauri_utils::display_path(bin_path));
|
||||
|
||||
let app_settings = interface.app_settings();
|
||||
|
||||
if !options.no_bundle && (config_.bundle.active || options.bundles.is_some()) {
|
||||
if !options.no_bundle && (config.bundle.active || options.bundles.is_some()) {
|
||||
crate::bundle::bundle(
|
||||
&options.into(),
|
||||
verbosity,
|
||||
ci,
|
||||
&interface,
|
||||
&*app_settings,
|
||||
config_,
|
||||
&config,
|
||||
&dirs,
|
||||
&out_dir,
|
||||
)?;
|
||||
}
|
||||
@ -145,14 +141,13 @@ pub fn setup(
|
||||
interface: &AppInterface,
|
||||
options: &mut Options,
|
||||
config: &ConfigMetadata,
|
||||
dirs: &Dirs,
|
||||
mobile: bool,
|
||||
) -> Result<()> {
|
||||
let tauri_path = tauri_dir();
|
||||
|
||||
// TODO: Maybe optimize this to run in parallel in the future
|
||||
// see https://github.com/tauri-apps/tauri/pull/13993#discussion_r2280697117
|
||||
log::info!("Looking up installed tauri packages to check mismatched versions...");
|
||||
if let Err(error) = check_mismatched_packages(frontend_dir(), tauri_path) {
|
||||
if let Err(error) = check_mismatched_packages(dirs.frontend, dirs.tauri) {
|
||||
if options.ignore_version_mismatches {
|
||||
log::error!("{error}");
|
||||
} else {
|
||||
@ -160,7 +155,7 @@ pub fn setup(
|
||||
}
|
||||
}
|
||||
|
||||
set_current_dir(tauri_path).context("failed to set current directory")?;
|
||||
set_current_dir(dirs.tauri).context("failed to set current directory")?;
|
||||
|
||||
let bundle_identifier_source = config
|
||||
.find_bundle_identifier_overwriter()
|
||||
@ -191,7 +186,13 @@ pub fn setup(
|
||||
}
|
||||
|
||||
if let Some(before_build) = config.build.before_build_command.clone() {
|
||||
helpers::run_hook("beforeBuildCommand", before_build, interface, options.debug)?;
|
||||
helpers::run_hook(
|
||||
"beforeBuildCommand",
|
||||
before_build,
|
||||
interface,
|
||||
options.debug,
|
||||
dirs.frontend,
|
||||
)?;
|
||||
}
|
||||
|
||||
if let Some(FrontendDist::Directory(web_asset_path)) = &config.build.frontend_dist {
|
||||
@ -219,7 +220,7 @@ pub fn setup(
|
||||
|
||||
// Issue #13287 - Allow the use of target dir inside frontendDist/distDir
|
||||
// https://github.com/tauri-apps/tauri/issues/13287
|
||||
let target_path = get_cargo_target_dir(&options.args)?;
|
||||
let target_path = get_cargo_target_dir(&options.args, dirs.tauri)?;
|
||||
let mut out_folders = Vec::new();
|
||||
if let Ok(web_asset_canonical) = dunce::canonicalize(web_asset_path) {
|
||||
if let Ok(relative_path) = target_path.strip_prefix(&web_asset_canonical) {
|
||||
@ -252,8 +253,7 @@ pub fn setup(
|
||||
|
||||
options
|
||||
.features
|
||||
.get_or_insert(Vec::new())
|
||||
.extend(config.build.features.clone().unwrap_or_default());
|
||||
.extend_from_slice(config.build.features.as_deref().unwrap_or_default());
|
||||
interface.build_options(&mut options.args, &mut options.features, mobile);
|
||||
|
||||
Ok(())
|
||||
|
||||
@ -16,8 +16,8 @@ use crate::{
|
||||
error::{Context, ErrorExt},
|
||||
helpers::{
|
||||
self,
|
||||
app_paths::tauri_dir,
|
||||
config::{get as get_config, ConfigMetadata},
|
||||
app_paths::Dirs,
|
||||
config::{get_config, ConfigMetadata},
|
||||
updater_signature,
|
||||
},
|
||||
interface::{AppInterface, AppSettings, Interface},
|
||||
@ -71,7 +71,7 @@ pub struct Options {
|
||||
pub config: Vec<ConfigValue>,
|
||||
/// Space or comma separated list of features, should be the same features passed to `tauri build` if any.
|
||||
#[clap(short, long, action = ArgAction::Append, num_args(0..))]
|
||||
pub features: Option<Vec<String>>,
|
||||
pub features: Vec<String>,
|
||||
/// Target triple to build against.
|
||||
///
|
||||
/// It must be one of the values outputted by `$rustc --print target-list` or `universal-apple-darwin` for an universal macOS application.
|
||||
@ -118,7 +118,7 @@ impl From<crate::build::Options> for Options {
|
||||
}
|
||||
|
||||
pub fn command(options: Options, verbosity: u8) -> crate::Result<()> {
|
||||
crate::helpers::app_paths::resolve();
|
||||
let dirs = crate::helpers::app_paths::resolve_dirs();
|
||||
|
||||
let ci = options.ci;
|
||||
|
||||
@ -131,27 +131,21 @@ pub fn command(options: Options, verbosity: u8) -> crate::Result<()> {
|
||||
let config = get_config(
|
||||
target,
|
||||
&options.config.iter().map(|c| &c.0).collect::<Vec<_>>(),
|
||||
dirs.tauri,
|
||||
)?;
|
||||
|
||||
let interface = AppInterface::new(
|
||||
config.lock().unwrap().as_ref().unwrap(),
|
||||
options.target.clone(),
|
||||
)?;
|
||||
let interface = AppInterface::new(&config, options.target.clone(), dirs.tauri)?;
|
||||
|
||||
let tauri_path = tauri_dir();
|
||||
std::env::set_current_dir(tauri_path).context("failed to set current directory")?;
|
||||
std::env::set_current_dir(dirs.tauri).context("failed to set current directory")?;
|
||||
|
||||
let config_guard = config.lock().unwrap();
|
||||
let config_ = config_guard.as_ref().unwrap();
|
||||
|
||||
if let Some(minimum_system_version) = &config_.bundle.macos.minimum_system_version {
|
||||
if let Some(minimum_system_version) = &config.bundle.macos.minimum_system_version {
|
||||
std::env::set_var("MACOSX_DEPLOYMENT_TARGET", minimum_system_version);
|
||||
}
|
||||
|
||||
let app_settings = interface.app_settings();
|
||||
let interface_options = options.clone().into();
|
||||
|
||||
let out_dir = app_settings.out_dir(&interface_options)?;
|
||||
let out_dir = app_settings.out_dir(&interface_options, dirs.tauri)?;
|
||||
|
||||
bundle(
|
||||
&options,
|
||||
@ -159,7 +153,8 @@ pub fn command(options: Options, verbosity: u8) -> crate::Result<()> {
|
||||
ci,
|
||||
&interface,
|
||||
&*app_settings,
|
||||
config_,
|
||||
&config,
|
||||
&dirs,
|
||||
&out_dir,
|
||||
)
|
||||
}
|
||||
@ -172,6 +167,7 @@ pub fn bundle<A: AppSettings>(
|
||||
interface: &AppInterface,
|
||||
app_settings: &A,
|
||||
config: &ConfigMetadata,
|
||||
dirs: &Dirs,
|
||||
out_dir: &Path,
|
||||
) -> crate::Result<()> {
|
||||
let package_types: Vec<PackageType> = if let Some(bundles) = &options.bundles {
|
||||
@ -198,12 +194,19 @@ pub fn bundle<A: AppSettings>(
|
||||
before_bundle,
|
||||
interface,
|
||||
options.debug,
|
||||
dirs.frontend,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
let mut settings = app_settings
|
||||
.get_bundler_settings(options.clone().into(), config, out_dir, package_types)
|
||||
.get_bundler_settings(
|
||||
options.clone().into(),
|
||||
config,
|
||||
out_dir,
|
||||
package_types,
|
||||
dirs.tauri,
|
||||
)
|
||||
.with_context(|| "failed to build bundler settings")?;
|
||||
settings.set_no_sign(options.no_sign);
|
||||
|
||||
|
||||
@ -5,11 +5,9 @@
|
||||
use crate::{
|
||||
error::{Context, ErrorExt},
|
||||
helpers::{
|
||||
app_paths::{frontend_dir, tauri_dir},
|
||||
app_paths::Dirs,
|
||||
command_env,
|
||||
config::{
|
||||
get as get_config, reload as reload_config, BeforeDevCommand, ConfigHandle, FrontendDist,
|
||||
},
|
||||
config::{get_config, reload_config, BeforeDevCommand, ConfigMetadata, FrontendDist},
|
||||
},
|
||||
info::plugins::check_mismatched_packages,
|
||||
interface::{AppInterface, ExitReason, Interface},
|
||||
@ -57,7 +55,7 @@ pub struct Options {
|
||||
pub target: Option<String>,
|
||||
/// List of cargo features to activate
|
||||
#[clap(short, long, action = ArgAction::Append, num_args(0..))]
|
||||
pub features: Option<Vec<String>>,
|
||||
pub features: Vec<String>,
|
||||
/// Exit on panic
|
||||
#[clap(short, long)]
|
||||
pub exit_on_panic: bool,
|
||||
@ -99,61 +97,57 @@ pub struct Options {
|
||||
}
|
||||
|
||||
pub fn command(options: Options) -> Result<()> {
|
||||
crate::helpers::app_paths::resolve();
|
||||
let dirs = crate::helpers::app_paths::resolve_dirs();
|
||||
|
||||
let r = command_internal(options);
|
||||
let r = command_internal(options, dirs);
|
||||
if r.is_err() {
|
||||
kill_before_dev_process();
|
||||
}
|
||||
r
|
||||
}
|
||||
|
||||
fn command_internal(mut options: Options) -> Result<()> {
|
||||
fn command_internal(mut options: Options, dirs: Dirs) -> Result<()> {
|
||||
let target = options
|
||||
.target
|
||||
.as_deref()
|
||||
.map(Target::from_triple)
|
||||
.unwrap_or_else(Target::current);
|
||||
|
||||
let config = get_config(
|
||||
let mut config = get_config(
|
||||
target,
|
||||
&options.config.iter().map(|c| &c.0).collect::<Vec<_>>(),
|
||||
dirs.tauri,
|
||||
)?;
|
||||
|
||||
let mut interface = AppInterface::new(
|
||||
config.lock().unwrap().as_ref().unwrap(),
|
||||
options.target.clone(),
|
||||
)?;
|
||||
let mut interface = AppInterface::new(&config, options.target.clone(), dirs.tauri)?;
|
||||
|
||||
setup(&interface, &mut options, config)?;
|
||||
setup(&interface, &mut options, &mut config, &dirs)?;
|
||||
|
||||
let exit_on_panic = options.exit_on_panic;
|
||||
let no_watch = options.no_watch;
|
||||
interface.dev(options.into(), move |status, reason| {
|
||||
on_app_exit(status, reason, exit_on_panic, no_watch)
|
||||
})
|
||||
interface.dev(
|
||||
&mut config,
|
||||
options.into(),
|
||||
move |status, reason| on_app_exit(status, reason, exit_on_panic, no_watch),
|
||||
&dirs,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn setup(interface: &AppInterface, options: &mut Options, config: ConfigHandle) -> Result<()> {
|
||||
let tauri_path = tauri_dir();
|
||||
|
||||
pub fn setup(
|
||||
interface: &AppInterface,
|
||||
options: &mut Options,
|
||||
config: &mut ConfigMetadata,
|
||||
dirs: &Dirs,
|
||||
) -> Result<()> {
|
||||
std::thread::spawn(|| {
|
||||
if let Err(error) = check_mismatched_packages(frontend_dir(), tauri_path) {
|
||||
if let Err(error) = check_mismatched_packages(dirs.frontend, dirs.tauri) {
|
||||
log::error!("{error}");
|
||||
}
|
||||
});
|
||||
|
||||
set_current_dir(tauri_path).context("failed to set current directory")?;
|
||||
set_current_dir(dirs.tauri).context("failed to set current directory")?;
|
||||
|
||||
if let Some(before_dev) = config
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.build
|
||||
.before_dev_command
|
||||
.clone()
|
||||
{
|
||||
if let Some(before_dev) = config.build.before_dev_command.clone() {
|
||||
let (script, script_cwd, wait) = match before_dev {
|
||||
BeforeDevCommand::Script(s) if s.is_empty() => (None, None, false),
|
||||
BeforeDevCommand::Script(s) => (Some(s), None, false),
|
||||
@ -161,7 +155,7 @@ pub fn setup(interface: &AppInterface, options: &mut Options, config: ConfigHand
|
||||
(Some(script), cwd.map(Into::into), wait)
|
||||
}
|
||||
};
|
||||
let cwd = script_cwd.unwrap_or_else(|| frontend_dir().clone());
|
||||
let cwd = script_cwd.unwrap_or_else(|| dirs.frontend.to_owned());
|
||||
if let Some(before_dev) = script {
|
||||
log::info!(action = "Running"; "BeforeDevCommand (`{}`)", before_dev);
|
||||
let mut env = command_env(true);
|
||||
@ -235,45 +229,14 @@ pub fn setup(interface: &AppInterface, options: &mut Options, config: ConfigHand
|
||||
}
|
||||
|
||||
if options.runner.is_none() {
|
||||
options.runner = config
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.build
|
||||
.runner
|
||||
.clone();
|
||||
options.runner = config.build.runner.clone();
|
||||
}
|
||||
|
||||
let mut cargo_features = config
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.build
|
||||
.features
|
||||
.clone()
|
||||
.unwrap_or_default();
|
||||
if let Some(features) = &options.features {
|
||||
cargo_features.extend(features.clone());
|
||||
}
|
||||
let mut cargo_features = config.build.features.clone().unwrap_or_default();
|
||||
cargo_features.extend(options.features.clone());
|
||||
|
||||
let mut dev_url = config
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.build
|
||||
.dev_url
|
||||
.clone();
|
||||
let frontend_dist = config
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.build
|
||||
.frontend_dist
|
||||
.clone();
|
||||
let mut dev_url = config.build.dev_url.clone();
|
||||
let frontend_dist = config.build.frontend_dist.clone();
|
||||
if !options.no_dev_server && dev_url.is_none() {
|
||||
if let Some(FrontendDist::Directory(path)) = &frontend_dist {
|
||||
if path.exists() {
|
||||
@ -296,7 +259,11 @@ pub fn setup(interface: &AppInterface, options: &mut Options, config: ConfigHand
|
||||
}
|
||||
})));
|
||||
|
||||
reload_config(&options.config.iter().map(|c| &c.0).collect::<Vec<_>>())?;
|
||||
reload_config(
|
||||
config,
|
||||
&options.config.iter().map(|c| &c.0).collect::<Vec<_>>(),
|
||||
dirs.tauri,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -349,16 +316,9 @@ pub fn setup(interface: &AppInterface, options: &mut Options, config: ConfigHand
|
||||
}
|
||||
|
||||
if options.additional_watch_folders.is_empty() {
|
||||
options.additional_watch_folders.extend(
|
||||
config
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.build
|
||||
.additional_watch_folders
|
||||
.clone(),
|
||||
);
|
||||
options
|
||||
.additional_watch_folders
|
||||
.extend(config.build.additional_watch_folders.clone());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@ -23,6 +23,11 @@ const ENV_TAURI_APP_PATH: &str = "TAURI_APP_PATH";
|
||||
// path to the frontend app directory, usually `<project>/`
|
||||
const ENV_TAURI_FRONTEND_PATH: &str = "TAURI_FRONTEND_PATH";
|
||||
|
||||
pub struct Dirs {
|
||||
pub tauri: &'static Path,
|
||||
pub frontend: &'static Path,
|
||||
}
|
||||
|
||||
static FRONTEND_DIR: OnceLock<PathBuf> = OnceLock::new();
|
||||
static TAURI_DIR: OnceLock<PathBuf> = OnceLock::new();
|
||||
|
||||
@ -122,8 +127,8 @@ pub fn resolve_tauri_dir() -> Option<PathBuf> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn resolve() {
|
||||
TAURI_DIR.set(resolve_tauri_dir().unwrap_or_else(|| {
|
||||
pub fn resolve_dirs() -> Dirs {
|
||||
let tauri = TAURI_DIR.get_or_init(|| resolve_tauri_dir().unwrap_or_else(|| {
|
||||
let env_var_name = env_tauri_app_path().is_some().then(|| format!("`{ENV_TAURI_APP_PATH}`"));
|
||||
panic!("Couldn't recognize the {} folder as a Tauri project. It must contain a `{}`, `{}` or `{}` file in any subfolder.",
|
||||
env_var_name.as_deref().unwrap_or("current"),
|
||||
@ -131,16 +136,11 @@ pub fn resolve() {
|
||||
ConfigFormat::Json5.into_file_name(),
|
||||
ConfigFormat::Toml.into_file_name()
|
||||
)
|
||||
})).expect("tauri dir already resolved");
|
||||
FRONTEND_DIR
|
||||
.set(resolve_frontend_dir().unwrap_or_else(|| tauri_dir().parent().unwrap().to_path_buf()))
|
||||
.expect("app dir already resolved");
|
||||
}
|
||||
|
||||
pub fn tauri_dir() -> &'static PathBuf {
|
||||
TAURI_DIR
|
||||
.get()
|
||||
.expect("app paths not initialized, this is a Tauri CLI bug")
|
||||
}));
|
||||
let frontend = FRONTEND_DIR.get_or_init(|| {
|
||||
resolve_frontend_dir().unwrap_or_else(|| tauri.parent().unwrap().to_path_buf())
|
||||
});
|
||||
Dirs { tauri, frontend }
|
||||
}
|
||||
|
||||
pub fn resolve_frontend_dir() -> Option<PathBuf> {
|
||||
@ -165,9 +165,3 @@ pub fn resolve_frontend_dir() -> Option<PathBuf> {
|
||||
})
|
||||
.map(|p| p.parent().unwrap().to_path_buf())
|
||||
}
|
||||
|
||||
pub fn frontend_dir() -> &'static PathBuf {
|
||||
FRONTEND_DIR
|
||||
.get()
|
||||
.expect("app paths not initialized, this is a Tauri CLI bug")
|
||||
}
|
||||
|
||||
@ -56,7 +56,7 @@ pub fn cargo_manifest_and_lock(tauri_dir: &Path) -> (Option<CargoManifest>, Opti
|
||||
.ok()
|
||||
.and_then(|manifest_contents| toml::from_str(&manifest_contents).ok());
|
||||
|
||||
let lock: Option<CargoLock> = get_workspace_dir()
|
||||
let lock: Option<CargoLock> = get_workspace_dir(tauri_dir)
|
||||
.ok()
|
||||
.and_then(|p| fs::read_to_string(p.join("Cargo.lock")).ok())
|
||||
.and_then(|s| toml::from_str(&s).ok());
|
||||
|
||||
@ -13,8 +13,9 @@ use std::{
|
||||
collections::HashMap,
|
||||
env::{current_dir, set_current_dir, set_var},
|
||||
ffi::{OsStr, OsString},
|
||||
path::Path,
|
||||
process::exit,
|
||||
sync::Mutex,
|
||||
sync::OnceLock,
|
||||
};
|
||||
|
||||
use crate::error::Context;
|
||||
@ -54,8 +55,7 @@ impl ConfigMetadata {
|
||||
for (ext, config) in &self.extensions {
|
||||
if let Some(identifier) = config
|
||||
.as_object()
|
||||
.and_then(|bundle_config| bundle_config.get("identifier"))
|
||||
.and_then(|id| id.as_str())
|
||||
.and_then(|bundle_config| bundle_config.get("identifier")?.as_str())
|
||||
{
|
||||
if identifier == self.inner.identifier {
|
||||
return Some(ext.clone());
|
||||
@ -66,14 +66,11 @@ impl ConfigMetadata {
|
||||
}
|
||||
}
|
||||
|
||||
pub type ConfigHandle = &'static Mutex<Option<ConfigMetadata>>;
|
||||
|
||||
pub fn wix_settings(config: WixConfig) -> tauri_bundler::WixSettings {
|
||||
tauri_bundler::WixSettings {
|
||||
version: config.version,
|
||||
upgrade_code: config.upgrade_code,
|
||||
fips_compliant: std::env::var("TAURI_BUNDLER_WIX_FIPS_COMPLIANT")
|
||||
.ok()
|
||||
fips_compliant: std::env::var_os("TAURI_BUNDLER_WIX_FIPS_COMPLIANT")
|
||||
.map(|v| v == "true")
|
||||
.unwrap_or(config.fips_compliant),
|
||||
language: tauri_bundler::WixLanguage(match config.language {
|
||||
@ -141,22 +138,22 @@ pub fn custom_sign_settings(
|
||||
}
|
||||
}
|
||||
|
||||
fn config_handle() -> ConfigHandle {
|
||||
static CONFIG_HANDLE: Mutex<Option<ConfigMetadata>> = Mutex::new(None);
|
||||
&CONFIG_HANDLE
|
||||
fn config_schema_validator() -> &'static jsonschema::Validator {
|
||||
// TODO: Switch to `LazyLock` when we bump MSRV to above 1.80
|
||||
static CONFIG_SCHEMA_VALIDATOR: OnceLock<jsonschema::Validator> = OnceLock::new();
|
||||
CONFIG_SCHEMA_VALIDATOR.get_or_init(|| {
|
||||
let schema: JsonValue = serde_json::from_str(include_str!("../../config.schema.json"))
|
||||
.expect("Failed to parse config schema bundled in the tauri-cli");
|
||||
jsonschema::validator_for(&schema).expect("Config schema bundled in the tauri-cli is invalid")
|
||||
})
|
||||
}
|
||||
|
||||
/// Gets the static parsed config from `tauri.conf.json`.
|
||||
fn get_internal(
|
||||
fn load_config(
|
||||
merge_configs: &[&serde_json::Value],
|
||||
reload: bool,
|
||||
target: Target,
|
||||
) -> crate::Result<ConfigHandle> {
|
||||
if !reload && config_handle().lock().unwrap().is_some() {
|
||||
return Ok(config_handle());
|
||||
}
|
||||
|
||||
let tauri_dir = super::app_paths::tauri_dir();
|
||||
tauri_dir: &Path,
|
||||
) -> crate::Result<ConfigMetadata> {
|
||||
let (mut config, config_path) =
|
||||
tauri_utils::config::parse::parse_value(target, tauri_dir.join("tauri.conf.json"))
|
||||
.context("failed to parse config")?;
|
||||
@ -165,8 +162,7 @@ fn get_internal(
|
||||
|
||||
let original_identifier = config
|
||||
.as_object()
|
||||
.and_then(|config| config.get("identifier"))
|
||||
.and_then(|id| id.as_str())
|
||||
.and_then(|config| config.get("identifier")?.as_str())
|
||||
.map(ToString::to_string);
|
||||
|
||||
if let Some((platform_config, config_path)) =
|
||||
@ -192,17 +188,14 @@ fn get_internal(
|
||||
if config_path.extension() == Some(OsStr::new("json"))
|
||||
|| config_path.extension() == Some(OsStr::new("json5"))
|
||||
{
|
||||
let schema: JsonValue = serde_json::from_str(include_str!("../../config.schema.json"))
|
||||
.context("failed to parse config schema")?;
|
||||
let validator = jsonschema::validator_for(&schema).expect("Invalid schema");
|
||||
let mut errors = validator.iter_errors(&config).peekable();
|
||||
let mut errors = config_schema_validator().iter_errors(&config).peekable();
|
||||
if errors.peek().is_some() {
|
||||
for error in errors {
|
||||
let path = error.instance_path.into_iter().join(" > ");
|
||||
if path.is_empty() {
|
||||
log::error!("`{config_file_name:?}` error: {}", error);
|
||||
log::error!("`{config_file_name:?}` error: {error}");
|
||||
} else {
|
||||
log::error!("`{config_file_name:?}` error on `{}`: {}", path, error);
|
||||
log::error!("`{config_file_name:?}` error on `{path}`: {error}");
|
||||
}
|
||||
}
|
||||
if !reload {
|
||||
@ -233,59 +226,54 @@ fn get_internal(
|
||||
std::env::set_var(REMOVE_UNUSED_COMMANDS_ENV_VAR, tauri_dir);
|
||||
}
|
||||
|
||||
*config_handle().lock().unwrap() = Some(ConfigMetadata {
|
||||
Ok(ConfigMetadata {
|
||||
target,
|
||||
original_identifier,
|
||||
inner: config,
|
||||
extensions,
|
||||
});
|
||||
|
||||
Ok(config_handle())
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get(target: Target, merge_configs: &[&serde_json::Value]) -> crate::Result<ConfigHandle> {
|
||||
get_internal(merge_configs, false, target)
|
||||
pub fn get_config(
|
||||
target: Target,
|
||||
merge_configs: &[&serde_json::Value],
|
||||
tauri_dir: &Path,
|
||||
) -> crate::Result<ConfigMetadata> {
|
||||
load_config(merge_configs, false, target, tauri_dir)
|
||||
}
|
||||
|
||||
pub fn reload(merge_configs: &[&serde_json::Value]) -> crate::Result<ConfigHandle> {
|
||||
let target = config_handle()
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.map(|conf| conf.target);
|
||||
if let Some(target) = target {
|
||||
get_internal(merge_configs, true, target)
|
||||
} else {
|
||||
crate::error::bail!("config not loaded");
|
||||
}
|
||||
pub fn reload_config(
|
||||
config: &mut ConfigMetadata,
|
||||
merge_configs: &[&serde_json::Value],
|
||||
tauri_dir: &Path,
|
||||
) -> crate::Result<()> {
|
||||
let target = config.target;
|
||||
*config = load_config(merge_configs, true, target, tauri_dir)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// merges the loaded config with the given value
|
||||
pub fn merge_with(merge_configs: &[&serde_json::Value]) -> crate::Result<ConfigHandle> {
|
||||
let handle = config_handle();
|
||||
|
||||
pub fn merge_config_with(
|
||||
config: &mut ConfigMetadata,
|
||||
merge_configs: &[&serde_json::Value],
|
||||
) -> crate::Result<()> {
|
||||
if merge_configs.is_empty() {
|
||||
return Ok(handle);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Some(config_metadata) = &mut *handle.lock().unwrap() {
|
||||
let mut merge_config = serde_json::Value::Object(Default::default());
|
||||
for conf in merge_configs {
|
||||
merge_patches(&mut merge_config, conf);
|
||||
}
|
||||
|
||||
let merge_config_str = serde_json::to_string(&merge_config).unwrap();
|
||||
set_var("TAURI_CONFIG", merge_config_str);
|
||||
|
||||
let mut value =
|
||||
serde_json::to_value(config_metadata.inner.clone()).context("failed to serialize config")?;
|
||||
merge(&mut value, &merge_config);
|
||||
config_metadata.inner = serde_json::from_value(value).context("failed to parse config")?;
|
||||
|
||||
Ok(handle)
|
||||
} else {
|
||||
crate::error::bail!("config not loaded");
|
||||
let mut merge_config = serde_json::Value::Object(Default::default());
|
||||
for conf in merge_configs {
|
||||
merge_patches(&mut merge_config, conf);
|
||||
}
|
||||
|
||||
let merge_config_str = serde_json::to_string(&merge_config).unwrap();
|
||||
set_var("TAURI_CONFIG", merge_config_str);
|
||||
|
||||
let mut value =
|
||||
serde_json::to_value(config.inner.clone()).context("failed to serialize config")?;
|
||||
merge(&mut value, &merge_config);
|
||||
config.inner = serde_json::from_value(value).context("failed to parse config")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Same as [`json_patch::merge`] but doesn't delete the key when the patch's value is `null`
|
||||
|
||||
@ -35,8 +35,6 @@ use crate::{
|
||||
CommandExt,
|
||||
};
|
||||
|
||||
use self::app_paths::frontend_dir;
|
||||
|
||||
pub fn command_env(debug: bool) -> HashMap<&'static str, String> {
|
||||
let mut map = HashMap::new();
|
||||
|
||||
@ -78,13 +76,14 @@ pub fn run_hook(
|
||||
hook: HookCommand,
|
||||
interface: &AppInterface,
|
||||
debug: bool,
|
||||
frontend_dir: &Path,
|
||||
) -> crate::Result<()> {
|
||||
let (script, script_cwd) = match hook {
|
||||
HookCommand::Script(s) if s.is_empty() => (None, None),
|
||||
HookCommand::Script(s) => (Some(s), None),
|
||||
HookCommand::ScriptWithOptions { script, cwd } => (Some(script), cwd.map(Into::into)),
|
||||
};
|
||||
let cwd = script_cwd.unwrap_or_else(|| frontend_dir().clone());
|
||||
let cwd = script_cwd.unwrap_or_else(|| frontend_dir.to_owned());
|
||||
if let Some(script) = script {
|
||||
log::info!(action = "Running"; "{} `{}`", name, script);
|
||||
|
||||
|
||||
@ -120,9 +120,14 @@ where
|
||||
{
|
||||
let bin_path = bin_path.as_ref();
|
||||
// We need to append .sig at the end it's where the signature will be stored
|
||||
let mut extension = bin_path.extension().unwrap().to_os_string();
|
||||
extension.push(".sig");
|
||||
let signature_path = bin_path.with_extension(extension);
|
||||
// TODO: use with_added_extension when we bump MSRV to > 1.91'
|
||||
let signature_path = if let Some(ext) = bin_path.extension() {
|
||||
let mut extension = ext.to_os_string();
|
||||
extension.push(".sig");
|
||||
bin_path.with_extension(extension)
|
||||
} else {
|
||||
bin_path.with_extension("sig")
|
||||
};
|
||||
|
||||
let trusted_comment = format!(
|
||||
"timestamp:{}\tfile:{}",
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
|
||||
use crate::{
|
||||
error::{Context, Error, ErrorExt},
|
||||
helpers::app_paths::tauri_dir,
|
||||
Result,
|
||||
};
|
||||
|
||||
@ -237,8 +236,8 @@ fn parse_bg_color(bg_color_string: &String) -> Result<Rgba<u8>> {
|
||||
pub fn command(options: Options) -> Result<()> {
|
||||
let input = options.input;
|
||||
let out_dir = options.output.unwrap_or_else(|| {
|
||||
crate::helpers::app_paths::resolve();
|
||||
tauri_dir().join("icons")
|
||||
let dirs = crate::helpers::app_paths::resolve_dirs();
|
||||
dirs.tauri.join("icons")
|
||||
});
|
||||
let png_icon_sizes = options.png.unwrap_or_default();
|
||||
|
||||
|
||||
@ -3,56 +3,46 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use super::SectionItem;
|
||||
use crate::helpers::config::ConfigMetadata;
|
||||
use crate::helpers::framework;
|
||||
use std::{
|
||||
fs::read_to_string,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use tauri_utils::platform::Target;
|
||||
use std::{fs::read_to_string, path::PathBuf};
|
||||
|
||||
pub fn items(frontend_dir: Option<&PathBuf>, tauri_dir: Option<&Path>) -> Vec<SectionItem> {
|
||||
pub fn items(config: &ConfigMetadata, frontend_dir: Option<&PathBuf>) -> Vec<SectionItem> {
|
||||
let mut items = Vec::new();
|
||||
if tauri_dir.is_some() {
|
||||
if let Ok(config) = crate::helpers::config::get(Target::current(), &[]) {
|
||||
let config_guard = config.lock().unwrap();
|
||||
let config = config_guard.as_ref().unwrap();
|
||||
let bundle_or_build = if config.bundle.active {
|
||||
"bundle"
|
||||
} else {
|
||||
"build"
|
||||
};
|
||||
items.push(SectionItem::new().description(format!("build-type: {bundle_or_build}")));
|
||||
|
||||
let bundle_or_build = if config.bundle.active {
|
||||
"bundle"
|
||||
} else {
|
||||
"build"
|
||||
};
|
||||
items.push(SectionItem::new().description(format!("build-type: {bundle_or_build}")));
|
||||
let csp = config
|
||||
.app
|
||||
.security
|
||||
.csp
|
||||
.clone()
|
||||
.map(|c| c.to_string())
|
||||
.unwrap_or_else(|| "unset".to_string());
|
||||
items.push(SectionItem::new().description(format!("CSP: {csp}")));
|
||||
|
||||
let csp = config
|
||||
.app
|
||||
.security
|
||||
.csp
|
||||
.clone()
|
||||
.map(|c| c.to_string())
|
||||
.unwrap_or_else(|| "unset".to_string());
|
||||
items.push(SectionItem::new().description(format!("CSP: {csp}")));
|
||||
if let Some(frontend_dist) = &config.build.frontend_dist {
|
||||
items.push(SectionItem::new().description(format!("frontendDist: {frontend_dist}")));
|
||||
}
|
||||
|
||||
if let Some(frontend_dist) = &config.build.frontend_dist {
|
||||
items.push(SectionItem::new().description(format!("frontendDist: {frontend_dist}")));
|
||||
if let Some(dev_url) = &config.build.dev_url {
|
||||
items.push(SectionItem::new().description(format!("devUrl: {dev_url}")));
|
||||
}
|
||||
|
||||
if let Some(frontend_dir) = frontend_dir {
|
||||
if let Ok(package_json) = read_to_string(frontend_dir.join("package.json")) {
|
||||
let (framework, bundler) = framework::infer_from_package_json(&package_json);
|
||||
|
||||
if let Some(framework) = framework {
|
||||
items.push(SectionItem::new().description(format!("framework: {framework}")));
|
||||
}
|
||||
|
||||
if let Some(dev_url) = &config.build.dev_url {
|
||||
items.push(SectionItem::new().description(format!("devUrl: {dev_url}")));
|
||||
}
|
||||
|
||||
if let Some(frontend_dir) = frontend_dir {
|
||||
if let Ok(package_json) = read_to_string(frontend_dir.join("package.json")) {
|
||||
let (framework, bundler) = framework::infer_from_package_json(&package_json);
|
||||
|
||||
if let Some(framework) = framework {
|
||||
items.push(SectionItem::new().description(format!("framework: {framework}")));
|
||||
}
|
||||
|
||||
if let Some(bundler) = bundler {
|
||||
items.push(SectionItem::new().description(format!("bundler: {bundler}")));
|
||||
}
|
||||
}
|
||||
if let Some(bundler) = bundler {
|
||||
items.push(SectionItem::new().description(format!("bundler: {bundler}")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@ use colored::{ColoredString, Colorize};
|
||||
use dialoguer::{theme::ColorfulTheme, Confirm};
|
||||
use serde::Deserialize;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use tauri_utils::platform::Target;
|
||||
|
||||
mod app;
|
||||
mod env_nodejs;
|
||||
@ -265,11 +266,6 @@ pub fn command(options: Options) -> Result<()> {
|
||||
let frontend_dir = resolve_frontend_dir();
|
||||
let tauri_dir = resolve_tauri_dir();
|
||||
|
||||
if tauri_dir.is_some() {
|
||||
// safe to initialize
|
||||
crate::helpers::app_paths::resolve();
|
||||
}
|
||||
|
||||
let package_manager = frontend_dir
|
||||
.as_ref()
|
||||
.map(packages_nodejs::package_manager)
|
||||
@ -313,9 +309,11 @@ pub fn command(options: Options) -> Result<()> {
|
||||
interactive,
|
||||
items: Vec::new(),
|
||||
};
|
||||
app
|
||||
.items
|
||||
.extend(app::items(frontend_dir.as_ref(), tauri_dir.as_deref()));
|
||||
if let Some(tauri_dir) = &tauri_dir {
|
||||
if let Ok(config) = crate::helpers::config::get_config(Target::current(), &[], tauri_dir) {
|
||||
app.items.extend(app::items(&config, frontend_dir.as_ref()));
|
||||
};
|
||||
}
|
||||
|
||||
environment.display();
|
||||
|
||||
|
||||
@ -111,33 +111,27 @@ pub fn items(
|
||||
) -> Vec<SectionItem> {
|
||||
let mut items = Vec::new();
|
||||
|
||||
if tauri_dir.is_some() || frontend_dir.is_some() {
|
||||
if let Some(tauri_dir) = tauri_dir {
|
||||
let (manifest, lock) = cargo_manifest_and_lock(tauri_dir);
|
||||
if let Some(tauri_dir) = tauri_dir {
|
||||
let (manifest, lock) = cargo_manifest_and_lock(tauri_dir);
|
||||
|
||||
for p in helpers::plugins::known_plugins().keys() {
|
||||
let dep = format!("tauri-plugin-{p}");
|
||||
let crate_version = crate_version(tauri_dir, manifest.as_ref(), lock.as_ref(), &dep);
|
||||
if !crate_version.has_version() {
|
||||
continue;
|
||||
}
|
||||
let item = packages_rust::rust_section_item(&dep, crate_version);
|
||||
items.push(item);
|
||||
|
||||
let Some(frontend_dir) = frontend_dir else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let package = format!("@tauri-apps/plugin-{p}");
|
||||
|
||||
let item = packages_nodejs::nodejs_section_item(
|
||||
package,
|
||||
None,
|
||||
frontend_dir.clone(),
|
||||
package_manager,
|
||||
);
|
||||
items.push(item);
|
||||
for p in helpers::plugins::known_plugins().keys() {
|
||||
let dep = format!("tauri-plugin-{p}");
|
||||
let crate_version = crate_version(tauri_dir, manifest.as_ref(), lock.as_ref(), &dep);
|
||||
if !crate_version.has_version() {
|
||||
continue;
|
||||
}
|
||||
let item = packages_rust::rust_section_item(&dep, crate_version);
|
||||
items.push(item);
|
||||
|
||||
let Some(frontend_dir) = frontend_dir else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let package = format!("@tauri-apps/plugin-{p}");
|
||||
|
||||
let item =
|
||||
packages_nodejs::nodejs_section_item(package, None, frontend_dir.clone(), package_manager);
|
||||
items.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
use std::path::Path;
|
||||
|
||||
use crate::Result;
|
||||
use clap::{Parser, Subcommand};
|
||||
@ -8,7 +9,7 @@ use clap::{Parser, Subcommand};
|
||||
use crate::interface::{AppInterface, AppSettings, Interface};
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[clap(about = "Manage or create permissions for your app or plugin")]
|
||||
#[clap(about = "Inspect values used by Tauri")]
|
||||
pub struct Cli {
|
||||
#[clap(subcommand)]
|
||||
command: Commands,
|
||||
@ -21,36 +22,34 @@ enum Commands {
|
||||
}
|
||||
|
||||
pub fn command(cli: Cli) -> Result<()> {
|
||||
let dirs = crate::helpers::app_paths::resolve_dirs();
|
||||
match cli.command {
|
||||
Commands::WixUpgradeCode => wix_upgrade_code(),
|
||||
Commands::WixUpgradeCode => wix_upgrade_code(dirs.tauri),
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: if this is ever changed, make sure to also update Wix upgrade code generation in tauri-bundler
|
||||
fn wix_upgrade_code() -> Result<()> {
|
||||
crate::helpers::app_paths::resolve();
|
||||
|
||||
fn wix_upgrade_code(tauri_dir: &Path) -> Result<()> {
|
||||
let target = tauri_utils::platform::Target::Windows;
|
||||
let config = crate::helpers::config::get(target, &[])?;
|
||||
let config = crate::helpers::config::get_config(target, &[], tauri_dir)?;
|
||||
|
||||
let interface = AppInterface::new(config.lock().unwrap().as_ref().unwrap(), None)?;
|
||||
let interface = AppInterface::new(&config, None, tauri_dir)?;
|
||||
|
||||
let product_name = interface.app_settings().get_package_settings().product_name;
|
||||
|
||||
let upgrade_code = uuid::Uuid::new_v5(
|
||||
&uuid::Uuid::NAMESPACE_DNS,
|
||||
format!("{product_name}.exe.app.x64").as_bytes(),
|
||||
)
|
||||
.to_string();
|
||||
);
|
||||
|
||||
log::info!("Default WiX Upgrade Code, derived from {product_name}: {upgrade_code}");
|
||||
if let Some(code) = config.lock().unwrap().as_ref().and_then(|c| {
|
||||
c.bundle
|
||||
.windows
|
||||
.wix
|
||||
.as_ref()
|
||||
.and_then(|wix| wix.upgrade_code)
|
||||
}) {
|
||||
if let Some(code) = config
|
||||
.bundle
|
||||
.windows
|
||||
.wix
|
||||
.as_ref()
|
||||
.and_then(|wix| wix.upgrade_code)
|
||||
{
|
||||
log::info!("Application Upgrade Code override: {code}");
|
||||
}
|
||||
|
||||
|
||||
@ -11,7 +11,10 @@ use std::{
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use crate::{error::Context, helpers::config::Config};
|
||||
use crate::{
|
||||
error::Context, helpers::app_paths::Dirs, helpers::config::Config,
|
||||
helpers::config::ConfigMetadata,
|
||||
};
|
||||
use tauri_bundler::bundle::{PackageType, Settings, SettingsBuilder};
|
||||
|
||||
pub use rust::{MobileOptions, Options, Rust as AppInterface, WatcherOptions};
|
||||
@ -32,9 +35,14 @@ pub trait AppSettings {
|
||||
options: &Options,
|
||||
config: &Config,
|
||||
features: &[String],
|
||||
tauri_dir: &Path,
|
||||
) -> crate::Result<tauri_bundler::BundleSettings>;
|
||||
fn app_binary_path(&self, options: &Options) -> crate::Result<PathBuf>;
|
||||
fn get_binaries(&self, options: &Options) -> crate::Result<Vec<tauri_bundler::BundleBinary>>;
|
||||
fn app_binary_path(&self, options: &Options, tauri_dir: &Path) -> crate::Result<PathBuf>;
|
||||
fn get_binaries(
|
||||
&self,
|
||||
options: &Options,
|
||||
tauri_dir: &Path,
|
||||
) -> crate::Result<Vec<tauri_bundler::BundleBinary>>;
|
||||
fn app_name(&self) -> Option<String>;
|
||||
fn lib_name(&self) -> Option<String>;
|
||||
|
||||
@ -44,9 +52,10 @@ pub trait AppSettings {
|
||||
config: &Config,
|
||||
out_dir: &Path,
|
||||
package_types: Vec<PackageType>,
|
||||
tauri_dir: &Path,
|
||||
) -> crate::Result<Settings> {
|
||||
let no_default_features = options.args.contains(&"--no-default-features".into());
|
||||
let mut enabled_features = options.features.clone().unwrap_or_default();
|
||||
let mut enabled_features = options.features.clone();
|
||||
if !no_default_features {
|
||||
enabled_features.push("default".into());
|
||||
}
|
||||
@ -57,7 +66,7 @@ pub trait AppSettings {
|
||||
tauri_utils::platform::target_triple().context("failed to get target triple")?
|
||||
};
|
||||
|
||||
let mut bins = self.get_binaries(&options)?;
|
||||
let mut bins = self.get_binaries(&options, tauri_dir)?;
|
||||
if let Some(main_binary_name) = &config.main_binary_name {
|
||||
let main = bins.iter_mut().find(|b| b.main()).context("no main bin?")?;
|
||||
main.set_name(main_binary_name.to_owned());
|
||||
@ -65,7 +74,7 @@ pub trait AppSettings {
|
||||
|
||||
let mut settings_builder = SettingsBuilder::new()
|
||||
.package_settings(self.get_package_settings())
|
||||
.bundle_settings(self.get_bundle_settings(&options, config, &enabled_features)?)
|
||||
.bundle_settings(self.get_bundle_settings(&options, config, &enabled_features, tauri_dir)?)
|
||||
.binaries(bins)
|
||||
.project_out_directory(out_dir)
|
||||
.target(target)
|
||||
@ -73,7 +82,7 @@ pub trait AppSettings {
|
||||
|
||||
if config.bundle.use_local_tools_dir {
|
||||
settings_builder = settings_builder.local_tools_directory(
|
||||
rust::get_cargo_metadata()
|
||||
rust::get_cargo_metadata(tauri_dir)
|
||||
.context("failed to get cargo metadata")?
|
||||
.target_directory,
|
||||
)
|
||||
@ -99,23 +108,31 @@ pub enum ExitReason {
|
||||
pub trait Interface: Sized {
|
||||
type AppSettings: AppSettings;
|
||||
|
||||
fn new(config: &Config, target: Option<String>) -> crate::Result<Self>;
|
||||
fn new(config: &Config, target: Option<String>, tauri_dir: &Path) -> crate::Result<Self>;
|
||||
fn app_settings(&self) -> Arc<Self::AppSettings>;
|
||||
fn env(&self) -> HashMap<&str, String>;
|
||||
fn build(&mut self, options: Options) -> crate::Result<PathBuf>;
|
||||
fn build(&mut self, options: Options, dirs: &Dirs) -> crate::Result<PathBuf>;
|
||||
fn dev<F: Fn(Option<i32>, ExitReason) + Send + Sync + 'static>(
|
||||
&mut self,
|
||||
config: &mut ConfigMetadata,
|
||||
options: Options,
|
||||
on_exit: F,
|
||||
dirs: &Dirs,
|
||||
) -> crate::Result<()>;
|
||||
fn mobile_dev<R: Fn(MobileOptions) -> crate::Result<Box<dyn DevProcess + Send>>>(
|
||||
fn mobile_dev<
|
||||
R: Fn(MobileOptions, &ConfigMetadata) -> crate::Result<Box<dyn DevProcess + Send>>,
|
||||
>(
|
||||
&mut self,
|
||||
config: &mut ConfigMetadata,
|
||||
options: MobileOptions,
|
||||
runner: R,
|
||||
dirs: &Dirs,
|
||||
) -> crate::Result<()>;
|
||||
fn watch<R: Fn() -> crate::Result<Box<dyn DevProcess + Send>>>(
|
||||
fn watch<R: Fn(&ConfigMetadata) -> crate::Result<Box<dyn DevProcess + Send>>>(
|
||||
&mut self,
|
||||
config: &mut ConfigMetadata,
|
||||
options: WatcherOptions,
|
||||
runner: R,
|
||||
dirs: &Dirs,
|
||||
) -> crate::Result<()>;
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ use std::{
|
||||
ffi::OsStr,
|
||||
fs::FileType,
|
||||
io::{BufRead, Write},
|
||||
iter::once,
|
||||
path::{Path, PathBuf},
|
||||
process::Command,
|
||||
str::FromStr,
|
||||
@ -15,7 +16,6 @@ use std::{
|
||||
};
|
||||
|
||||
use dunce::canonicalize;
|
||||
use glob::glob;
|
||||
use ignore::gitignore::{Gitignore, GitignoreBuilder};
|
||||
use notify::RecursiveMode;
|
||||
use notify_debouncer_full::new_debouncer;
|
||||
@ -31,8 +31,8 @@ use super::{AppSettings, DevProcess, ExitReason, Interface};
|
||||
use crate::{
|
||||
error::{Context, Error, ErrorExt},
|
||||
helpers::{
|
||||
app_paths::{frontend_dir, tauri_dir},
|
||||
config::{nsis_settings, reload as reload_config, wix_settings, BundleResources, Config},
|
||||
app_paths::Dirs,
|
||||
config::{nsis_settings, reload_config, wix_settings, BundleResources, Config, ConfigMetadata},
|
||||
},
|
||||
ConfigValue,
|
||||
};
|
||||
@ -51,7 +51,7 @@ pub struct Options {
|
||||
pub runner: Option<RunnerConfig>,
|
||||
pub debug: bool,
|
||||
pub target: Option<String>,
|
||||
pub features: Option<Vec<String>>,
|
||||
pub features: Vec<String>,
|
||||
pub args: Vec<String>,
|
||||
pub config: Vec<ConfigValue>,
|
||||
pub no_watch: bool,
|
||||
@ -108,7 +108,7 @@ impl From<crate::dev::Options> for Options {
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MobileOptions {
|
||||
pub debug: bool,
|
||||
pub features: Option<Vec<String>>,
|
||||
pub features: Vec<String>,
|
||||
pub args: Vec<String>,
|
||||
pub config: Vec<ConfigValue>,
|
||||
pub no_watch: bool,
|
||||
@ -137,7 +137,7 @@ pub struct Rust {
|
||||
impl Interface for Rust {
|
||||
type AppSettings = RustAppSettings;
|
||||
|
||||
fn new(config: &Config, target: Option<String>) -> crate::Result<Self> {
|
||||
fn new(config: &Config, target: Option<String>, tauri_dir: &Path) -> crate::Result<Self> {
|
||||
let manifest = {
|
||||
let (tx, rx) = sync_channel(1);
|
||||
let mut watcher = new_debouncer(Duration::from_secs(1), None, move |r| {
|
||||
@ -147,14 +147,9 @@ impl Interface for Rust {
|
||||
})
|
||||
.unwrap();
|
||||
watcher
|
||||
.watch(tauri_dir().join("Cargo.toml"), RecursiveMode::NonRecursive)
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"failed to watch {}",
|
||||
tauri_dir().join("Cargo.toml").display()
|
||||
)
|
||||
})?;
|
||||
let (manifest, modified) = rewrite_manifest(config)?;
|
||||
.watch(tauri_dir.join("Cargo.toml"), RecursiveMode::NonRecursive)
|
||||
.with_context(|| format!("failed to watch {}", tauri_dir.join("Cargo.toml").display()))?;
|
||||
let (manifest, modified) = rewrite_manifest(config, tauri_dir)?;
|
||||
if modified {
|
||||
// Wait for the modified event so we don't trigger a re-build later on
|
||||
let _ = rx.recv_timeout(Duration::from_secs(2));
|
||||
@ -172,7 +167,7 @@ impl Interface for Rust {
|
||||
);
|
||||
}
|
||||
|
||||
let app_settings = RustAppSettings::new(config, manifest, target)?;
|
||||
let app_settings = RustAppSettings::new(config, manifest, target, tauri_dir)?;
|
||||
|
||||
Ok(Self {
|
||||
app_settings: Arc::new(app_settings),
|
||||
@ -186,20 +181,23 @@ impl Interface for Rust {
|
||||
self.app_settings.clone()
|
||||
}
|
||||
|
||||
fn build(&mut self, options: Options) -> crate::Result<PathBuf> {
|
||||
fn build(&mut self, options: Options, dirs: &Dirs) -> crate::Result<PathBuf> {
|
||||
desktop::build(
|
||||
options,
|
||||
&self.app_settings,
|
||||
&mut self.available_targets,
|
||||
self.config_features.clone(),
|
||||
self.main_binary_name.as_deref(),
|
||||
dirs.tauri,
|
||||
)
|
||||
}
|
||||
|
||||
fn dev<F: Fn(Option<i32>, ExitReason) + Send + Sync + 'static>(
|
||||
&mut self,
|
||||
config: &mut ConfigMetadata,
|
||||
mut options: Options,
|
||||
on_exit: F,
|
||||
dirs: &Dirs,
|
||||
) -> crate::Result<()> {
|
||||
let on_exit = Arc::new(on_exit);
|
||||
|
||||
@ -223,20 +221,29 @@ impl Interface for Rust {
|
||||
Ok(())
|
||||
} else {
|
||||
let merge_configs = options.config.iter().map(|c| &c.0).collect::<Vec<_>>();
|
||||
let run = Arc::new(|rust: &mut Rust| {
|
||||
let on_exit = on_exit.clone();
|
||||
rust.run_dev(options.clone(), run_args.clone(), move |status, reason| {
|
||||
on_exit(status, reason)
|
||||
})
|
||||
});
|
||||
self.run_dev_watcher(&options.additional_watch_folders, &merge_configs, run)
|
||||
self.run_dev_watcher(
|
||||
config,
|
||||
&options.additional_watch_folders,
|
||||
&merge_configs,
|
||||
|rust: &mut Rust, _config| {
|
||||
let on_exit = on_exit.clone();
|
||||
rust.run_dev(options.clone(), run_args.clone(), move |status, reason| {
|
||||
on_exit(status, reason)
|
||||
})
|
||||
},
|
||||
dirs,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn mobile_dev<R: Fn(MobileOptions) -> crate::Result<Box<dyn DevProcess + Send>>>(
|
||||
fn mobile_dev<
|
||||
R: Fn(MobileOptions, &ConfigMetadata) -> crate::Result<Box<dyn DevProcess + Send>>,
|
||||
>(
|
||||
&mut self,
|
||||
config: &mut ConfigMetadata,
|
||||
mut options: MobileOptions,
|
||||
runner: R,
|
||||
dirs: &Dirs,
|
||||
) -> crate::Result<()> {
|
||||
let mut run_args = Vec::new();
|
||||
dev_options(
|
||||
@ -248,27 +255,36 @@ impl Interface for Rust {
|
||||
);
|
||||
|
||||
if options.no_watch {
|
||||
runner(options)?;
|
||||
runner(options, config)?;
|
||||
Ok(())
|
||||
} else {
|
||||
self.watch(
|
||||
config,
|
||||
WatcherOptions {
|
||||
config: options.config.clone(),
|
||||
additional_watch_folders: options.additional_watch_folders.clone(),
|
||||
},
|
||||
move || runner(options.clone()),
|
||||
move |config| runner(options.clone(), config),
|
||||
dirs,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn watch<R: Fn() -> crate::Result<Box<dyn DevProcess + Send>>>(
|
||||
fn watch<R: Fn(&ConfigMetadata) -> crate::Result<Box<dyn DevProcess + Send>>>(
|
||||
&mut self,
|
||||
config: &mut ConfigMetadata,
|
||||
options: WatcherOptions,
|
||||
runner: R,
|
||||
dirs: &Dirs,
|
||||
) -> crate::Result<()> {
|
||||
let merge_configs = options.config.iter().map(|c| &c.0).collect::<Vec<_>>();
|
||||
let run = Arc::new(|_rust: &mut Rust| runner());
|
||||
self.run_dev_watcher(&options.additional_watch_folders, &merge_configs, run)
|
||||
self.run_dev_watcher(
|
||||
config,
|
||||
&options.additional_watch_folders,
|
||||
&merge_configs,
|
||||
|_rust: &mut Rust, config| runner(config),
|
||||
dirs,
|
||||
)
|
||||
}
|
||||
|
||||
fn env(&self) -> HashMap<&str, String> {
|
||||
@ -393,7 +409,7 @@ fn dev_options(
|
||||
mobile: bool,
|
||||
args: &mut Vec<String>,
|
||||
run_args: &mut Vec<String>,
|
||||
features: &mut Option<Vec<String>>,
|
||||
features: &mut Vec<String>,
|
||||
app_settings: &RustAppSettings,
|
||||
) {
|
||||
let mut dev_args = Vec::new();
|
||||
@ -429,35 +445,25 @@ fn dev_options(
|
||||
})
|
||||
.collect();
|
||||
args.push("--no-default-features".into());
|
||||
if !enable_features.is_empty() {
|
||||
features.get_or_insert(Vec::new()).extend(enable_features);
|
||||
}
|
||||
features.extend(enable_features);
|
||||
}
|
||||
}
|
||||
|
||||
// Copied from https://github.com/rust-lang/cargo/blob/69255bb10de7f74511b5cef900a9d102247b6029/src/cargo/core/workspace.rs#L665
|
||||
fn expand_member_path(path: &Path) -> crate::Result<Vec<PathBuf>> {
|
||||
let path = path.to_str().context("path is not UTF-8 compatible")?;
|
||||
let res = glob(path).with_context(|| format!("failed to expand glob pattern for {path}"))?;
|
||||
let res = res
|
||||
.map(|p| p.with_context(|| format!("failed to expand glob pattern for {path}")))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn get_watch_folders(additional_watch_folders: &[PathBuf]) -> crate::Result<Vec<PathBuf>> {
|
||||
let tauri_path = tauri_dir();
|
||||
let workspace_path = get_workspace_dir()?;
|
||||
|
||||
fn get_watch_folders(
|
||||
additional_watch_folders: &[PathBuf],
|
||||
tauri_dir: &Path,
|
||||
) -> crate::Result<Vec<PathBuf>> {
|
||||
// We always want to watch the main tauri folder.
|
||||
let mut watch_folders = vec![tauri_path.to_path_buf()];
|
||||
let mut watch_folders = vec![tauri_dir.to_path_buf()];
|
||||
|
||||
watch_folders.extend(get_in_workspace_dependency_paths(tauri_dir)?);
|
||||
|
||||
// Add the additional watch folders, resolving the path from the tauri path if it is relative
|
||||
watch_folders.extend(additional_watch_folders.iter().filter_map(|dir| {
|
||||
let path = if dir.is_absolute() {
|
||||
dir.to_owned()
|
||||
} else {
|
||||
tauri_path.join(dir)
|
||||
tauri_dir.join(dir)
|
||||
};
|
||||
|
||||
let canonicalized = canonicalize(&path).ok();
|
||||
@ -470,43 +476,12 @@ fn get_watch_folders(additional_watch_folders: &[PathBuf]) -> crate::Result<Vec<
|
||||
canonicalized
|
||||
}));
|
||||
|
||||
// We also try to watch workspace members, no matter if the tauri cargo project is the workspace root or a workspace member
|
||||
let cargo_settings = CargoSettings::load(&workspace_path)?;
|
||||
if let Some(members) = cargo_settings.workspace.and_then(|w| w.members) {
|
||||
for p in members {
|
||||
let p = workspace_path.join(p);
|
||||
match expand_member_path(&p) {
|
||||
// Sometimes expand_member_path returns an empty vec, for example if the path contains `[]` as in `C:/[abc]/project/`.
|
||||
// Cargo won't complain unless theres a workspace.members config with glob patterns so we should support it too.
|
||||
Ok(expanded_paths) => {
|
||||
if expanded_paths.is_empty() {
|
||||
watch_folders.push(p);
|
||||
} else {
|
||||
watch_folders.extend(expanded_paths);
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
// If this fails cargo itself should fail too. But we still try to keep going with the unexpanded path.
|
||||
log::error!("Error watching {}: {}", p.display(), err.to_string());
|
||||
watch_folders.push(p);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Ok(watch_folders)
|
||||
}
|
||||
|
||||
impl Rust {
|
||||
pub fn build_options(
|
||||
&self,
|
||||
args: &mut Vec<String>,
|
||||
features: &mut Option<Vec<String>>,
|
||||
mobile: bool,
|
||||
) {
|
||||
features
|
||||
.get_or_insert(Vec::new())
|
||||
.push("tauri/custom-protocol".into());
|
||||
pub fn build_options(&self, args: &mut Vec<String>, features: &mut Vec<String>, mobile: bool) {
|
||||
features.push("tauri/custom-protocol".into());
|
||||
if mobile {
|
||||
args.push("--lib".into());
|
||||
} else {
|
||||
@ -530,22 +505,30 @@ impl Rust {
|
||||
.map(|c| Box::new(c) as Box<dyn DevProcess + Send>)
|
||||
}
|
||||
|
||||
fn run_dev_watcher<F: Fn(&mut Rust) -> crate::Result<Box<dyn DevProcess + Send>>>(
|
||||
fn run_dev_watcher<
|
||||
F: Fn(&mut Rust, &ConfigMetadata) -> crate::Result<Box<dyn DevProcess + Send>>,
|
||||
>(
|
||||
&mut self,
|
||||
config: &mut ConfigMetadata,
|
||||
additional_watch_folders: &[PathBuf],
|
||||
merge_configs: &[&serde_json::Value],
|
||||
run: Arc<F>,
|
||||
run: F,
|
||||
dirs: &Dirs,
|
||||
) -> crate::Result<()> {
|
||||
let child = run(self)?;
|
||||
let child = run(self, config)?;
|
||||
|
||||
let process = Arc::new(Mutex::new(child));
|
||||
let (tx, rx) = sync_channel(1);
|
||||
let frontend_path = frontend_dir();
|
||||
|
||||
let watch_folders = get_watch_folders(additional_watch_folders)?;
|
||||
let watch_folders = get_watch_folders(additional_watch_folders, dirs.tauri)?;
|
||||
|
||||
let common_ancestor = common_path::common_path_all(watch_folders.iter().map(Path::new))
|
||||
.expect("watch_folders should not be empty");
|
||||
let common_ancestor = common_path::common_path_all(
|
||||
watch_folders
|
||||
.iter()
|
||||
.map(Path::new)
|
||||
.chain(once(self.app_settings.workspace_dir.as_path())),
|
||||
)
|
||||
.expect("watch_folders should not be empty");
|
||||
let ignore_matcher = build_ignore_matcher(&common_ancestor);
|
||||
|
||||
let mut watcher = new_debouncer(Duration::from_secs(1), None, move |r| {
|
||||
@ -582,22 +565,21 @@ impl Rust {
|
||||
|
||||
if let Some(event_path) = event.paths.first() {
|
||||
if !ignore_matcher.is_ignore(event_path, event_path.is_dir()) {
|
||||
if is_configuration_file(self.app_settings.target_platform, event_path) {
|
||||
if let Ok(config) = reload_config(merge_configs) {
|
||||
let (manifest, modified) =
|
||||
rewrite_manifest(config.lock().unwrap().as_ref().unwrap())?;
|
||||
if modified {
|
||||
*self.app_settings.manifest.lock().unwrap() = manifest;
|
||||
// no need to run the watcher logic, the manifest was modified
|
||||
// and it will trigger the watcher again
|
||||
continue;
|
||||
}
|
||||
if is_configuration_file(self.app_settings.target_platform, event_path)
|
||||
&& reload_config(config, merge_configs, dirs.tauri).is_ok()
|
||||
{
|
||||
let (manifest, modified) = rewrite_manifest(config, dirs.tauri)?;
|
||||
if modified {
|
||||
*self.app_settings.manifest.lock().unwrap() = manifest;
|
||||
// no need to run the watcher logic, the manifest was modified
|
||||
// and it will trigger the watcher again
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
log::info!(
|
||||
"File {} changed. Rebuilding application...",
|
||||
display_path(event_path.strip_prefix(frontend_path).unwrap_or(event_path))
|
||||
display_path(event_path.strip_prefix(dirs.frontend).unwrap_or(event_path))
|
||||
);
|
||||
|
||||
let mut p = process.lock().unwrap();
|
||||
@ -610,7 +592,7 @@ impl Rust {
|
||||
break;
|
||||
}
|
||||
}
|
||||
*p = run(self)?;
|
||||
*p = run(self, config)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -681,7 +663,7 @@ pub struct TomlWorkspaceField {
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
struct WorkspaceSettings {
|
||||
/// the workspace members.
|
||||
members: Option<Vec<String>>,
|
||||
// members: Option<Vec<String>>,
|
||||
package: Option<WorkspacePackageSettings>,
|
||||
}
|
||||
|
||||
@ -768,6 +750,7 @@ pub struct RustAppSettings {
|
||||
cargo_config: CargoConfig,
|
||||
target_triple: String,
|
||||
target_platform: TargetPlatform,
|
||||
workspace_dir: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
@ -846,6 +829,7 @@ impl AppSettings for RustAppSettings {
|
||||
options: &Options,
|
||||
config: &Config,
|
||||
features: &[String],
|
||||
tauri_dir: &Path,
|
||||
) -> crate::Result<BundleSettings> {
|
||||
let arch64bits = self.target_triple.starts_with("x86_64")
|
||||
|| self.target_triple.starts_with("aarch64")
|
||||
@ -876,6 +860,7 @@ impl AppSettings for RustAppSettings {
|
||||
self,
|
||||
features,
|
||||
config,
|
||||
tauri_dir,
|
||||
config.bundle.clone(),
|
||||
updater_settings,
|
||||
arch64bits,
|
||||
@ -920,8 +905,8 @@ impl AppSettings for RustAppSettings {
|
||||
Ok(settings)
|
||||
}
|
||||
|
||||
fn app_binary_path(&self, options: &Options) -> crate::Result<PathBuf> {
|
||||
let binaries = self.get_binaries(options)?;
|
||||
fn app_binary_path(&self, options: &Options, tauri_dir: &Path) -> crate::Result<PathBuf> {
|
||||
let binaries = self.get_binaries(options, tauri_dir)?;
|
||||
let bin_name = binaries
|
||||
.iter()
|
||||
.find(|x| x.main())
|
||||
@ -929,7 +914,7 @@ impl AppSettings for RustAppSettings {
|
||||
.name();
|
||||
|
||||
let out_dir = self
|
||||
.out_dir(options)
|
||||
.out_dir(options, tauri_dir)
|
||||
.context("failed to get project out directory")?;
|
||||
|
||||
let mut path = out_dir.join(bin_name);
|
||||
@ -947,7 +932,7 @@ impl AppSettings for RustAppSettings {
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
fn get_binaries(&self, options: &Options) -> crate::Result<Vec<BundleBinary>> {
|
||||
fn get_binaries(&self, options: &Options, tauri_dir: &Path) -> crate::Result<Vec<BundleBinary>> {
|
||||
let mut binaries = Vec::new();
|
||||
|
||||
if let Some(bins) = &self.cargo_settings.bin {
|
||||
@ -957,11 +942,12 @@ impl AppSettings for RustAppSettings {
|
||||
.clone()
|
||||
.unwrap_or_default();
|
||||
for bin in bins {
|
||||
if let (Some(req_features), Some(opt_features)) =
|
||||
(&bin.required_features, &options.features)
|
||||
{
|
||||
if let Some(req_features) = &bin.required_features {
|
||||
// Check if all required features are enabled.
|
||||
if !req_features.iter().all(|feat| opt_features.contains(feat)) {
|
||||
if !req_features
|
||||
.iter()
|
||||
.all(|feat| options.features.contains(feat))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -975,8 +961,6 @@ impl AppSettings for RustAppSettings {
|
||||
}
|
||||
}
|
||||
|
||||
let tauri_dir = tauri_dir();
|
||||
|
||||
let mut binaries_paths = std::fs::read_dir(tauri_dir.join("src/bin"))
|
||||
.map(|dir| {
|
||||
dir
|
||||
@ -1068,8 +1052,12 @@ impl AppSettings for RustAppSettings {
|
||||
}
|
||||
|
||||
impl RustAppSettings {
|
||||
pub fn new(config: &Config, manifest: Manifest, target: Option<String>) -> crate::Result<Self> {
|
||||
let tauri_dir = tauri_dir();
|
||||
pub fn new(
|
||||
config: &Config,
|
||||
manifest: Manifest,
|
||||
target: Option<String>,
|
||||
tauri_dir: &Path,
|
||||
) -> crate::Result<Self> {
|
||||
let cargo_settings = CargoSettings::load(tauri_dir).context("failed to load Cargo settings")?;
|
||||
let cargo_package_settings = match &cargo_settings.package {
|
||||
Some(package_info) => package_info.clone(),
|
||||
@ -1080,7 +1068,8 @@ impl RustAppSettings {
|
||||
}
|
||||
};
|
||||
|
||||
let ws_package_settings = CargoSettings::load(&get_workspace_dir()?)
|
||||
let workspace_dir = get_workspace_dir(tauri_dir)?;
|
||||
let ws_package_settings = CargoSettings::load(&workspace_dir)
|
||||
.context("failed to load Cargo settings from workspace root")?
|
||||
.workspace
|
||||
.and_then(|v| v.package);
|
||||
@ -1175,6 +1164,7 @@ impl RustAppSettings {
|
||||
cargo_config,
|
||||
target_triple,
|
||||
target_platform,
|
||||
workspace_dir,
|
||||
})
|
||||
}
|
||||
|
||||
@ -1185,8 +1175,8 @@ impl RustAppSettings {
|
||||
.or_else(|| self.cargo_config.build().target())
|
||||
}
|
||||
|
||||
pub fn out_dir(&self, options: &Options) -> crate::Result<PathBuf> {
|
||||
get_target_dir(self.target(options), options)
|
||||
pub fn out_dir(&self, options: &Options, tauri_dir: &Path) -> crate::Result<PathBuf> {
|
||||
get_target_dir(self.target(options), options, tauri_dir)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1194,12 +1184,29 @@ impl RustAppSettings {
|
||||
pub(crate) struct CargoMetadata {
|
||||
pub(crate) target_directory: PathBuf,
|
||||
pub(crate) workspace_root: PathBuf,
|
||||
workspace_members: Vec<String>,
|
||||
packages: Vec<Package>,
|
||||
}
|
||||
|
||||
pub(crate) fn get_cargo_metadata() -> crate::Result<CargoMetadata> {
|
||||
#[derive(Deserialize)]
|
||||
struct Package {
|
||||
name: String,
|
||||
id: String,
|
||||
manifest_path: PathBuf,
|
||||
dependencies: Vec<Dependency>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Dependency {
|
||||
name: String,
|
||||
/// Local package
|
||||
path: Option<PathBuf>,
|
||||
}
|
||||
|
||||
pub(crate) fn get_cargo_metadata(tauri_dir: &Path) -> crate::Result<CargoMetadata> {
|
||||
let output = Command::new("cargo")
|
||||
.args(["metadata", "--no-deps", "--format-version", "1"])
|
||||
.current_dir(tauri_dir())
|
||||
.current_dir(tauri_dir)
|
||||
.output()
|
||||
.map_err(|error| Error::CommandFailed {
|
||||
command: "cargo metadata --no-deps --format-version 1".to_string(),
|
||||
@ -1216,16 +1223,66 @@ pub(crate) fn get_cargo_metadata() -> crate::Result<CargoMetadata> {
|
||||
serde_json::from_slice(&output.stdout).context("failed to parse cargo metadata")
|
||||
}
|
||||
|
||||
/// Get the tauri project crate's dependencies that are inside the workspace
|
||||
fn get_in_workspace_dependency_paths(tauri_dir: &Path) -> crate::Result<Vec<PathBuf>> {
|
||||
let metadata = get_cargo_metadata(tauri_dir)?;
|
||||
let tauri_project_manifest_path = tauri_dir.join("Cargo.toml");
|
||||
let tauri_project_package = metadata
|
||||
.packages
|
||||
.iter()
|
||||
.find(|package| package.manifest_path == tauri_project_manifest_path)
|
||||
.context("tauri project package doesn't exist in cargo metadata output `packages`")?;
|
||||
|
||||
let workspace_packages = metadata
|
||||
.workspace_members
|
||||
.iter()
|
||||
.map(|member_package_id| {
|
||||
metadata
|
||||
.packages
|
||||
.iter()
|
||||
.find(|package| package.id == *member_package_id)
|
||||
.context("workspace member doesn't exist in cargo metadata output `packages`")
|
||||
})
|
||||
.collect::<crate::Result<Vec<_>>>()?;
|
||||
|
||||
let mut found_dependency_paths = Vec::new();
|
||||
find_dependencies(
|
||||
tauri_project_package,
|
||||
&workspace_packages,
|
||||
&mut found_dependency_paths,
|
||||
);
|
||||
Ok(found_dependency_paths)
|
||||
}
|
||||
|
||||
fn find_dependencies(
|
||||
package: &Package,
|
||||
workspace_packages: &Vec<&Package>,
|
||||
found_dependency_paths: &mut Vec<PathBuf>,
|
||||
) {
|
||||
for dependency in &package.dependencies {
|
||||
if let Some(path) = &dependency.path {
|
||||
if let Some(package) = workspace_packages.iter().find(|workspace_package| {
|
||||
workspace_package.name == dependency.name
|
||||
&& path.join("Cargo.toml") == workspace_package.manifest_path
|
||||
&& !found_dependency_paths.contains(path)
|
||||
}) {
|
||||
found_dependency_paths.push(path.to_owned());
|
||||
find_dependencies(package, workspace_packages, found_dependency_paths);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the cargo target directory based on the provided arguments.
|
||||
/// If "--target-dir" is specified in args, use it as the target directory (relative to current directory).
|
||||
/// Otherwise, use the target directory from cargo metadata.
|
||||
pub(crate) fn get_cargo_target_dir(args: &[String]) -> crate::Result<PathBuf> {
|
||||
pub(crate) fn get_cargo_target_dir(args: &[String], tauri_dir: &Path) -> crate::Result<PathBuf> {
|
||||
let path = if let Some(target) = get_cargo_option(args, "--target-dir") {
|
||||
std::env::current_dir()
|
||||
.context("failed to get current directory")?
|
||||
.join(target)
|
||||
} else {
|
||||
get_cargo_metadata()
|
||||
get_cargo_metadata(tauri_dir)
|
||||
.context("failed to run 'cargo metadata' command to get target directory")?
|
||||
.target_directory
|
||||
};
|
||||
@ -1235,8 +1292,12 @@ pub(crate) fn get_cargo_target_dir(args: &[String]) -> crate::Result<PathBuf> {
|
||||
|
||||
/// This function determines the 'target' directory and suffixes it with the profile
|
||||
/// to determine where the compiled binary will be located.
|
||||
fn get_target_dir(triple: Option<&str>, options: &Options) -> crate::Result<PathBuf> {
|
||||
let mut path = get_cargo_target_dir(&options.args)?;
|
||||
fn get_target_dir(
|
||||
triple: Option<&str>,
|
||||
options: &Options,
|
||||
tauri_dir: &Path,
|
||||
) -> crate::Result<PathBuf> {
|
||||
let mut path = get_cargo_target_dir(&options.args, tauri_dir)?;
|
||||
|
||||
if let Some(triple) = triple {
|
||||
path.push(triple);
|
||||
@ -1261,9 +1322,9 @@ fn get_cargo_option<'a>(args: &'a [String], option: &'a str) -> Option<&'a str>
|
||||
}
|
||||
|
||||
/// Executes `cargo metadata` to get the workspace directory.
|
||||
pub fn get_workspace_dir() -> crate::Result<PathBuf> {
|
||||
pub fn get_workspace_dir(tauri_dir: &Path) -> crate::Result<PathBuf> {
|
||||
Ok(
|
||||
get_cargo_metadata()
|
||||
get_cargo_metadata(tauri_dir)
|
||||
.context("failed to run 'cargo metadata' command to get workspace directory")?
|
||||
.workspace_root,
|
||||
)
|
||||
@ -1289,6 +1350,7 @@ fn tauri_config_to_bundle_settings(
|
||||
settings: &RustAppSettings,
|
||||
features: &[String],
|
||||
tauri_config: &Config,
|
||||
tauri_dir: &Path,
|
||||
config: crate::helpers::config::BundleConfig,
|
||||
updater_config: Option<UpdaterSettings>,
|
||||
arch64bits: bool,
|
||||
@ -1433,14 +1495,16 @@ fn tauri_config_to_bundle_settings(
|
||||
.map(tauri_bundler::bundle::Entitlements::Path)
|
||||
} else {
|
||||
let mut app_links_entitlements = plist::Dictionary::new();
|
||||
app_links_entitlements.insert(
|
||||
"com.apple.developer.associated-domains".to_string(),
|
||||
domains
|
||||
.into_iter()
|
||||
.map(|domain| format!("applinks:{domain}").into())
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
);
|
||||
if !domains.is_empty() {
|
||||
app_links_entitlements.insert(
|
||||
"com.apple.developer.associated-domains".to_string(),
|
||||
domains
|
||||
.into_iter()
|
||||
.map(|domain| format!("applinks:{domain}").into())
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
let entitlements = if let Some(user_provided_entitlements) = config.macos.entitlements {
|
||||
crate::helpers::plist::merge_plist(vec![
|
||||
PathBuf::from(user_provided_entitlements).into(),
|
||||
@ -1570,7 +1634,7 @@ fn tauri_config_to_bundle_settings(
|
||||
info_plist: {
|
||||
let mut src_plists = vec![];
|
||||
|
||||
let path = tauri_dir().join("Info.plist");
|
||||
let path = tauri_dir.join("Info.plist");
|
||||
if path.exists() {
|
||||
src_plists.push(path.into());
|
||||
}
|
||||
@ -1612,7 +1676,7 @@ fn tauri_config_to_bundle_settings(
|
||||
.unwrap()
|
||||
})
|
||||
}),
|
||||
license_file: config.license_file.map(|l| tauri_dir().join(l)),
|
||||
license_file: config.license_file.map(|l| tauri_dir.join(l)),
|
||||
updater: updater_config,
|
||||
..Default::default()
|
||||
})
|
||||
@ -1749,7 +1813,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn parse_target_dir_from_opts() {
|
||||
crate::helpers::app_paths::resolve();
|
||||
let dirs = crate::helpers::app_paths::resolve_dirs();
|
||||
let current_dir = std::env::current_dir().unwrap();
|
||||
|
||||
let options = Options {
|
||||
@ -1766,11 +1830,11 @@ mod tests {
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
get_target_dir(None, &options).unwrap(),
|
||||
get_target_dir(None, &options, dirs.tauri).unwrap(),
|
||||
current_dir.join("path/to/some/dir/release")
|
||||
);
|
||||
assert_eq!(
|
||||
get_target_dir(Some("x86_64-pc-windows-msvc"), &options).unwrap(),
|
||||
get_target_dir(Some("x86_64-pc-windows-msvc"), &options, dirs.tauri).unwrap(),
|
||||
current_dir
|
||||
.join("path/to/some/dir")
|
||||
.join("x86_64-pc-windows-msvc")
|
||||
@ -1789,23 +1853,27 @@ mod tests {
|
||||
};
|
||||
|
||||
#[cfg(windows)]
|
||||
assert!(get_target_dir(Some("x86_64-pc-windows-msvc"), &options)
|
||||
.unwrap()
|
||||
.ends_with("x86_64-pc-windows-msvc\\release"));
|
||||
assert!(
|
||||
get_target_dir(Some("x86_64-pc-windows-msvc"), &options, dirs.tauri)
|
||||
.unwrap()
|
||||
.ends_with("x86_64-pc-windows-msvc\\release")
|
||||
);
|
||||
#[cfg(not(windows))]
|
||||
assert!(get_target_dir(Some("x86_64-pc-windows-msvc"), &options)
|
||||
.unwrap()
|
||||
.ends_with("x86_64-pc-windows-msvc/release"));
|
||||
assert!(
|
||||
get_target_dir(Some("x86_64-pc-windows-msvc"), &options, dirs.tauri)
|
||||
.unwrap()
|
||||
.ends_with("x86_64-pc-windows-msvc/release")
|
||||
);
|
||||
|
||||
#[cfg(windows)]
|
||||
{
|
||||
std::env::set_var("CARGO_TARGET_DIR", "D:\\path\\to\\env\\dir");
|
||||
assert_eq!(
|
||||
get_target_dir(None, &options).unwrap(),
|
||||
get_target_dir(None, &options, dirs.tauri).unwrap(),
|
||||
PathBuf::from("D:\\path\\to\\env\\dir\\release")
|
||||
);
|
||||
assert_eq!(
|
||||
get_target_dir(Some("x86_64-pc-windows-msvc"), &options).unwrap(),
|
||||
get_target_dir(Some("x86_64-pc-windows-msvc"), &options, dirs.tauri).unwrap(),
|
||||
PathBuf::from("D:\\path\\to\\env\\dir\\x86_64-pc-windows-msvc\\release")
|
||||
);
|
||||
}
|
||||
@ -1814,11 +1882,11 @@ mod tests {
|
||||
{
|
||||
std::env::set_var("CARGO_TARGET_DIR", "/path/to/env/dir");
|
||||
assert_eq!(
|
||||
get_target_dir(None, &options).unwrap(),
|
||||
get_target_dir(None, &options, dirs.tauri).unwrap(),
|
||||
PathBuf::from("/path/to/env/dir/release")
|
||||
);
|
||||
assert_eq!(
|
||||
get_target_dir(Some("x86_64-pc-windows-msvc"), &options).unwrap(),
|
||||
get_target_dir(Some("x86_64-pc-windows-msvc"), &options, dirs.tauri).unwrap(),
|
||||
PathBuf::from("/path/to/env/dir/x86_64-pc-windows-msvc/release")
|
||||
);
|
||||
}
|
||||
|
||||
@ -12,7 +12,7 @@ use shared_child::SharedChild;
|
||||
use std::{
|
||||
fs,
|
||||
io::{BufReader, ErrorKind, Write},
|
||||
path::PathBuf,
|
||||
path::{Path, PathBuf},
|
||||
process::{Command, ExitStatus, Stdio},
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
@ -158,9 +158,10 @@ pub fn build(
|
||||
available_targets: &mut Option<Vec<RustupTarget>>,
|
||||
config_features: Vec<String>,
|
||||
main_binary_name: Option<&str>,
|
||||
tauri_dir: &Path,
|
||||
) -> crate::Result<PathBuf> {
|
||||
let out_dir = app_settings.out_dir(&options)?;
|
||||
let bin_path = app_settings.app_binary_path(&options)?;
|
||||
let out_dir = app_settings.out_dir(&options, tauri_dir)?;
|
||||
let bin_path = app_settings.app_binary_path(&options, tauri_dir)?;
|
||||
|
||||
if !std::env::var("STATIC_VCRUNTIME").is_ok_and(|v| v == "false") {
|
||||
std::env::set_var("STATIC_VCRUNTIME", "true");
|
||||
@ -182,7 +183,7 @@ pub fn build(
|
||||
options.target.replace(triple.into());
|
||||
|
||||
let triple_out_dir = app_settings
|
||||
.out_dir(&options)
|
||||
.out_dir(&options, tauri_dir)
|
||||
.with_context(|| format!("failed to get {triple} out dir"))?;
|
||||
|
||||
build_production_app(options, available_targets, config_features.clone())
|
||||
@ -262,9 +263,7 @@ fn cargo_command(
|
||||
build_cmd.args(&options.args);
|
||||
|
||||
let mut features = config_features;
|
||||
if let Some(f) = options.features {
|
||||
features.extend(f);
|
||||
}
|
||||
features.extend(options.features);
|
||||
if !features.is_empty() {
|
||||
build_cmd.arg("--features");
|
||||
build_cmd.arg(features.join(","));
|
||||
|
||||
@ -4,10 +4,7 @@
|
||||
|
||||
use crate::{
|
||||
error::{Context, ErrorExt},
|
||||
helpers::{
|
||||
app_paths::tauri_dir,
|
||||
config::{Config, PatternKind},
|
||||
},
|
||||
helpers::config::{Config, PatternKind},
|
||||
};
|
||||
|
||||
use itertools::Itertools;
|
||||
@ -272,8 +269,8 @@ fn inject_features(
|
||||
Ok(persist)
|
||||
}
|
||||
|
||||
pub fn rewrite_manifest(config: &Config) -> crate::Result<(Manifest, bool)> {
|
||||
let manifest_path = tauri_dir().join("Cargo.toml");
|
||||
pub fn rewrite_manifest(config: &Config, tauri_dir: &Path) -> crate::Result<(Manifest, bool)> {
|
||||
let manifest_path = tauri_dir.join("Cargo.toml");
|
||||
let (mut manifest, original_manifest_str) = read_manifest(&manifest_path)?;
|
||||
|
||||
let mut dependencies = Vec::new();
|
||||
@ -354,10 +351,7 @@ mod tests {
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if let Some(f) = item_table
|
||||
.and_then(|t| t.get("features").cloned())
|
||||
.and_then(|f| f.as_array().cloned())
|
||||
{
|
||||
if let Some(f) = item_table.and_then(|t| t.get("features")?.as_array().cloned()) {
|
||||
for feature in f.iter() {
|
||||
let feature = feature.as_str().expect("feature is not a string");
|
||||
if !dep.all_cli_managed_features.contains(&feature) {
|
||||
|
||||
@ -2,35 +2,31 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use crate::{
|
||||
error::Context,
|
||||
helpers::app_paths::{frontend_dir, tauri_dir},
|
||||
Result,
|
||||
};
|
||||
use crate::{error::Context, helpers::app_paths::Dirs, Result};
|
||||
|
||||
mod config;
|
||||
mod frontend;
|
||||
mod manifest;
|
||||
|
||||
pub fn run() -> Result<()> {
|
||||
let tauri_dir = tauri_dir();
|
||||
let frontend_dir = frontend_dir();
|
||||
|
||||
let mut migrated = config::migrate(tauri_dir).context("Could not migrate config")?;
|
||||
manifest::migrate(tauri_dir).context("Could not migrate manifest")?;
|
||||
let plugins = frontend::migrate(frontend_dir)?;
|
||||
pub fn run(dirs: &Dirs) -> Result<()> {
|
||||
let mut migrated = config::migrate(dirs.tauri).context("Could not migrate config")?;
|
||||
manifest::migrate(dirs.tauri).context("Could not migrate manifest")?;
|
||||
let plugins = frontend::migrate(dirs.frontend)?;
|
||||
|
||||
migrated.plugins.extend(plugins);
|
||||
|
||||
// Add plugins
|
||||
for plugin in migrated.plugins {
|
||||
crate::add::run(crate::add::Options {
|
||||
plugin: plugin.clone(),
|
||||
branch: None,
|
||||
tag: None,
|
||||
rev: None,
|
||||
no_fmt: false,
|
||||
})
|
||||
crate::add::run(
|
||||
crate::add::Options {
|
||||
plugin: plugin.clone(),
|
||||
branch: None,
|
||||
tag: None,
|
||||
rev: None,
|
||||
no_fmt: false,
|
||||
},
|
||||
dirs,
|
||||
)
|
||||
.with_context(|| format!("Could not migrate plugin '{plugin}'"))?;
|
||||
}
|
||||
|
||||
|
||||
@ -4,10 +4,7 @@
|
||||
|
||||
use crate::{
|
||||
error::{Context, ErrorExt},
|
||||
helpers::{
|
||||
app_paths::{frontend_dir, tauri_dir},
|
||||
npm::PackageManager,
|
||||
},
|
||||
helpers::{app_paths::Dirs, npm::PackageManager},
|
||||
interface::rust::manifest::{read_manifest, serialize_manifest},
|
||||
Result,
|
||||
};
|
||||
@ -16,17 +13,14 @@ use std::{fs::read_to_string, path::Path};
|
||||
|
||||
use toml_edit::{DocumentMut, Item, Table, TableLike, Value};
|
||||
|
||||
pub fn run() -> Result<()> {
|
||||
let frontend_dir = frontend_dir();
|
||||
let tauri_dir = tauri_dir();
|
||||
|
||||
let manifest_path = tauri_dir.join("Cargo.toml");
|
||||
pub fn run(dirs: &Dirs) -> Result<()> {
|
||||
let manifest_path = dirs.tauri.join("Cargo.toml");
|
||||
let (mut manifest, _) = read_manifest(&manifest_path)?;
|
||||
migrate_manifest(&mut manifest)?;
|
||||
|
||||
migrate_permissions(tauri_dir)?;
|
||||
migrate_permissions(dirs.tauri)?;
|
||||
|
||||
migrate_npm_dependencies(frontend_dir)?;
|
||||
migrate_npm_dependencies(dirs.frontend)?;
|
||||
|
||||
std::fs::write(&manifest_path, serialize_manifest(&manifest))
|
||||
.fs_context("failed to rewrite Cargo manifest", &manifest_path)?;
|
||||
|
||||
@ -4,10 +4,7 @@
|
||||
|
||||
use crate::{
|
||||
error::{bail, Context, ErrorExt},
|
||||
helpers::{
|
||||
app_paths::tauri_dir,
|
||||
cargo_manifest::{crate_version, CargoLock, CargoManifest},
|
||||
},
|
||||
helpers::cargo_manifest::{crate_version, CargoLock, CargoManifest},
|
||||
interface::rust::get_workspace_dir,
|
||||
Result,
|
||||
};
|
||||
@ -17,22 +14,20 @@ use std::{fs::read_to_string, str::FromStr};
|
||||
mod migrations;
|
||||
|
||||
pub fn command() -> Result<()> {
|
||||
crate::helpers::app_paths::resolve();
|
||||
let dirs = crate::helpers::app_paths::resolve_dirs();
|
||||
|
||||
let tauri_dir = tauri_dir();
|
||||
|
||||
let manifest_contents = read_to_string(tauri_dir.join("Cargo.toml")).fs_context(
|
||||
let manifest_contents = read_to_string(dirs.tauri.join("Cargo.toml")).fs_context(
|
||||
"failed to read Cargo manifest",
|
||||
tauri_dir.join("Cargo.toml"),
|
||||
dirs.tauri.join("Cargo.toml"),
|
||||
)?;
|
||||
let manifest = toml::from_str::<CargoManifest>(&manifest_contents).with_context(|| {
|
||||
format!(
|
||||
"failed to parse Cargo manifest {}",
|
||||
tauri_dir.join("Cargo.toml").display()
|
||||
dirs.tauri.join("Cargo.toml").display()
|
||||
)
|
||||
})?;
|
||||
|
||||
let workspace_dir = get_workspace_dir()?;
|
||||
let workspace_dir = get_workspace_dir(dirs.tauri)?;
|
||||
let lock_path = workspace_dir.join("Cargo.lock");
|
||||
let lock = if lock_path.exists() {
|
||||
let lockfile_contents =
|
||||
@ -44,19 +39,19 @@ pub fn command() -> Result<()> {
|
||||
None
|
||||
};
|
||||
|
||||
let tauri_version = crate_version(tauri_dir, Some(&manifest), lock.as_ref(), "tauri")
|
||||
let tauri_version = crate_version(dirs.tauri, Some(&manifest), lock.as_ref(), "tauri")
|
||||
.version
|
||||
.context("failed to get tauri version")?;
|
||||
let tauri_version = semver::Version::from_str(&tauri_version)
|
||||
.with_context(|| format!("failed to parse tauri version {tauri_version}"))?;
|
||||
|
||||
if tauri_version.major == 1 {
|
||||
migrations::v1::run().context("failed to migrate from v1")?;
|
||||
migrations::v1::run(&dirs).context("failed to migrate from v1")?;
|
||||
} else if tauri_version.major == 2 {
|
||||
if let Some((pre, _number)) = tauri_version.pre.as_str().split_once('.') {
|
||||
match pre {
|
||||
"beta" => {
|
||||
migrations::v2_beta::run().context("failed to migrate from v2 beta")?;
|
||||
migrations::v2_beta::run(&dirs).context("failed to migrate from v2 beta")?;
|
||||
}
|
||||
"alpha" => {
|
||||
bail!(
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
use super::{detect_target_ok, ensure_init, env, get_app, get_config, read_options, MobileTarget};
|
||||
use crate::{
|
||||
error::{Context, ErrorExt},
|
||||
helpers::config::{get as get_tauri_config, reload as reload_tauri_config},
|
||||
helpers::config::{get_config as get_tauri_config, reload_config as reload_tauri_config},
|
||||
interface::{AppInterface, Interface},
|
||||
mobile::CliOptions,
|
||||
Error, Result,
|
||||
@ -38,7 +38,7 @@ pub struct Options {
|
||||
}
|
||||
|
||||
pub fn command(options: Options) -> Result<()> {
|
||||
crate::helpers::app_paths::resolve();
|
||||
let dirs = crate::helpers::app_paths::resolve_dirs();
|
||||
|
||||
let profile = if options.release {
|
||||
Profile::Release
|
||||
@ -46,41 +46,32 @@ pub fn command(options: Options) -> Result<()> {
|
||||
Profile::Debug
|
||||
};
|
||||
|
||||
let (tauri_config, cli_options) = {
|
||||
let tauri_config = get_tauri_config(tauri_utils::platform::Target::Android, &[])?;
|
||||
let cli_options = {
|
||||
let tauri_config_guard = tauri_config.lock().unwrap();
|
||||
let tauri_config_ = tauri_config_guard.as_ref().unwrap();
|
||||
read_options(tauri_config_)
|
||||
};
|
||||
let mut tauri_config = get_tauri_config(tauri_utils::platform::Target::Android, &[], dirs.tauri)?;
|
||||
let cli_options = read_options(&tauri_config);
|
||||
|
||||
let tauri_config = if cli_options.config.is_empty() {
|
||||
tauri_config
|
||||
} else {
|
||||
// reload config with merges from the android dev|build script
|
||||
reload_tauri_config(
|
||||
&cli_options
|
||||
.config
|
||||
.iter()
|
||||
.map(|conf| &conf.0)
|
||||
.collect::<Vec<_>>(),
|
||||
)?
|
||||
};
|
||||
|
||||
(tauri_config, cli_options)
|
||||
if !cli_options.config.is_empty() {
|
||||
// reload config with merges from the android dev|build script
|
||||
reload_tauri_config(
|
||||
&mut tauri_config,
|
||||
&cli_options
|
||||
.config
|
||||
.iter()
|
||||
.map(|conf| &conf.0)
|
||||
.collect::<Vec<_>>(),
|
||||
dirs.tauri,
|
||||
)?
|
||||
};
|
||||
|
||||
let (config, metadata) = {
|
||||
let tauri_config_guard = tauri_config.lock().unwrap();
|
||||
let tauri_config_ = tauri_config_guard.as_ref().unwrap();
|
||||
let (config, metadata) = get_config(
|
||||
&get_app(
|
||||
MobileTarget::Android,
|
||||
tauri_config_,
|
||||
&AppInterface::new(tauri_config_, None)?,
|
||||
&tauri_config,
|
||||
&AppInterface::new(&tauri_config, None, dirs.tauri)?,
|
||||
dirs.tauri,
|
||||
),
|
||||
tauri_config_,
|
||||
None,
|
||||
&tauri_config,
|
||||
&[],
|
||||
&cli_options,
|
||||
);
|
||||
(config, metadata)
|
||||
@ -95,7 +86,8 @@ pub fn command(options: Options) -> Result<()> {
|
||||
)?;
|
||||
|
||||
if !cli_options.config.is_empty() {
|
||||
crate::helpers::config::merge_with(
|
||||
crate::helpers::config::merge_config_with(
|
||||
&mut tauri_config,
|
||||
&cli_options
|
||||
.config
|
||||
.iter()
|
||||
@ -107,16 +99,7 @@ pub fn command(options: Options) -> Result<()> {
|
||||
let env = env(std::env::var("CI").is_ok())?;
|
||||
|
||||
if cli_options.dev {
|
||||
let dev_url = tauri_config
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.build
|
||||
.dev_url
|
||||
.clone();
|
||||
|
||||
if let Some(url) = dev_url {
|
||||
if let Some(url) = &tauri_config.build.dev_url {
|
||||
let localhost = match url.host() {
|
||||
Some(url::Host::Domain(d)) => d == "localhost",
|
||||
Some(url::Host::Ipv4(i)) => i == std::net::Ipv4Addr::LOCALHOST,
|
||||
|
||||
@ -10,8 +10,8 @@ use crate::{
|
||||
build::Options as BuildOptions,
|
||||
error::Context,
|
||||
helpers::{
|
||||
app_paths::tauri_dir,
|
||||
config::{get as get_tauri_config, ConfigHandle},
|
||||
app_paths::Dirs,
|
||||
config::{get_config as get_tauri_config, ConfigMetadata},
|
||||
flock,
|
||||
},
|
||||
interface::{AppInterface, Interface, Options as InterfaceOptions},
|
||||
@ -27,6 +27,7 @@ use cargo_mobile2::{
|
||||
};
|
||||
|
||||
use std::env::set_current_dir;
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug, Clone, Parser)]
|
||||
#[clap(
|
||||
@ -48,7 +49,7 @@ pub struct Options {
|
||||
pub targets: Option<Vec<String>>,
|
||||
/// List of cargo features to activate
|
||||
#[clap(short, long, action = ArgAction::Append, num_args(0..))]
|
||||
pub features: Option<Vec<String>>,
|
||||
pub features: Vec<String>,
|
||||
/// JSON strings or paths to JSON, JSON5 or TOML files to merge with the default configuration file
|
||||
///
|
||||
/// Configurations are merged in the order they are provided, which means a particular value overwrites previous values when a config key-value pair conflicts.
|
||||
@ -63,10 +64,12 @@ pub struct Options {
|
||||
pub split_per_abi: bool,
|
||||
/// Build APKs.
|
||||
#[clap(long)]
|
||||
pub apk: Option<bool>,
|
||||
pub apk: bool,
|
||||
/// Build AABs.
|
||||
#[clap(long)]
|
||||
pub aab: Option<bool>,
|
||||
pub aab: bool,
|
||||
#[clap(skip)]
|
||||
pub skip_bundle: bool,
|
||||
/// Open Android Studio
|
||||
#[clap(short, long)]
|
||||
pub open: bool,
|
||||
@ -116,8 +119,25 @@ pub struct BuiltApplication {
|
||||
}
|
||||
|
||||
pub fn command(options: Options, noise_level: NoiseLevel) -> Result<BuiltApplication> {
|
||||
crate::helpers::app_paths::resolve();
|
||||
let dirs = crate::helpers::app_paths::resolve_dirs();
|
||||
let tauri_config = get_tauri_config(
|
||||
tauri_utils::platform::Target::Android,
|
||||
&options
|
||||
.config
|
||||
.iter()
|
||||
.map(|conf| &conf.0)
|
||||
.collect::<Vec<_>>(),
|
||||
dirs.tauri,
|
||||
)?;
|
||||
run(options, noise_level, &dirs, &tauri_config)
|
||||
}
|
||||
|
||||
pub fn run(
|
||||
options: Options,
|
||||
noise_level: NoiseLevel,
|
||||
dirs: &Dirs,
|
||||
tauri_config: &ConfigMetadata,
|
||||
) -> Result<BuiltApplication> {
|
||||
delete_codegen_vars();
|
||||
|
||||
let mut build_options: BuildOptions = options.clone().into();
|
||||
@ -133,26 +153,15 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<BuiltApplica
|
||||
.unwrap();
|
||||
build_options.target = Some(first_target.triple.into());
|
||||
|
||||
let tauri_config = get_tauri_config(
|
||||
tauri_utils::platform::Target::Android,
|
||||
&options
|
||||
.config
|
||||
.iter()
|
||||
.map(|conf| &conf.0)
|
||||
.collect::<Vec<_>>(),
|
||||
)?;
|
||||
let (interface, config, metadata) = {
|
||||
let tauri_config_guard = tauri_config.lock().unwrap();
|
||||
let tauri_config_ = tauri_config_guard.as_ref().unwrap();
|
||||
|
||||
let interface = AppInterface::new(tauri_config_, build_options.target.clone())?;
|
||||
let interface = AppInterface::new(tauri_config, build_options.target.clone(), dirs.tauri)?;
|
||||
interface.build_options(&mut Vec::new(), &mut build_options.features, true);
|
||||
|
||||
let app = get_app(MobileTarget::Android, tauri_config_, &interface);
|
||||
let app = get_app(MobileTarget::Android, tauri_config, &interface, dirs.tauri);
|
||||
let (config, metadata) = get_config(
|
||||
&app,
|
||||
tauri_config_,
|
||||
build_options.features.as_ref(),
|
||||
tauri_config,
|
||||
&build_options.features,
|
||||
&Default::default(),
|
||||
);
|
||||
(interface, config, metadata)
|
||||
@ -164,11 +173,10 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<BuiltApplica
|
||||
Profile::Release
|
||||
};
|
||||
|
||||
let tauri_path = tauri_dir();
|
||||
set_current_dir(tauri_path).context("failed to set current directory to Tauri directory")?;
|
||||
set_current_dir(dirs.tauri).context("failed to set current directory to Tauri directory")?;
|
||||
|
||||
ensure_init(
|
||||
&tauri_config,
|
||||
tauri_config,
|
||||
config.app(),
|
||||
config.project_dir(),
|
||||
MobileTarget::Android,
|
||||
@ -178,18 +186,9 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<BuiltApplica
|
||||
let mut env = env(options.ci)?;
|
||||
configure_cargo(&mut env, &config)?;
|
||||
|
||||
generate_tauri_properties(
|
||||
&config,
|
||||
tauri_config.lock().unwrap().as_ref().unwrap(),
|
||||
false,
|
||||
)?;
|
||||
generate_tauri_properties(&config, tauri_config, false)?;
|
||||
|
||||
{
|
||||
let config_guard = tauri_config.lock().unwrap();
|
||||
let config_ = config_guard.as_ref().unwrap();
|
||||
|
||||
crate::build::setup(&interface, &mut build_options, config_, true)?;
|
||||
}
|
||||
crate::build::setup(&interface, &mut build_options, tauri_config, dirs, true)?;
|
||||
|
||||
let installed_targets =
|
||||
crate::interface::rust::installation::installed_targets().unwrap_or_default();
|
||||
@ -219,6 +218,7 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<BuiltApplica
|
||||
&config,
|
||||
&mut env,
|
||||
noise_level,
|
||||
dirs.tauri,
|
||||
)?;
|
||||
|
||||
if open {
|
||||
@ -237,16 +237,17 @@ fn run_build(
|
||||
interface: &AppInterface,
|
||||
mut options: Options,
|
||||
build_options: BuildOptions,
|
||||
tauri_config: ConfigHandle,
|
||||
tauri_config: &ConfigMetadata,
|
||||
profile: Profile,
|
||||
config: &AndroidConfig,
|
||||
env: &mut Env,
|
||||
noise_level: NoiseLevel,
|
||||
tauri_dir: &Path,
|
||||
) -> Result<OptionsHandle> {
|
||||
if !(options.apk.is_some() || options.aab.is_some()) {
|
||||
if !(options.skip_bundle || options.apk || options.aab) {
|
||||
// if the user didn't specify the format to build, we'll do both
|
||||
options.apk = Some(true);
|
||||
options.aab = Some(true);
|
||||
options.apk = true;
|
||||
options.aab = true;
|
||||
}
|
||||
|
||||
let interface_options = InterfaceOptions {
|
||||
@ -257,7 +258,7 @@ fn run_build(
|
||||
};
|
||||
|
||||
let app_settings = interface.app_settings();
|
||||
let out_dir = app_settings.out_dir(&interface_options)?;
|
||||
let out_dir = app_settings.out_dir(&interface_options, tauri_dir)?;
|
||||
let _lock = flock::open_rw(out_dir.join("lock").with_extension("android"), "Android")?;
|
||||
|
||||
let cli_options = CliOptions {
|
||||
@ -269,11 +270,11 @@ fn run_build(
|
||||
config: build_options.config,
|
||||
target_device: options.target_device.clone(),
|
||||
};
|
||||
let handle = write_options(tauri_config.lock().unwrap().as_ref().unwrap(), cli_options)?;
|
||||
let handle = write_options(tauri_config, cli_options)?;
|
||||
|
||||
inject_resources(config, tauri_config.lock().unwrap().as_ref().unwrap())?;
|
||||
inject_resources(config, tauri_config)?;
|
||||
|
||||
let apk_outputs = if options.apk.unwrap_or_default() {
|
||||
let apk_outputs = if options.apk {
|
||||
apk::build(
|
||||
config,
|
||||
env,
|
||||
@ -287,7 +288,7 @@ fn run_build(
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
let aab_outputs = if options.aab.unwrap_or_default() {
|
||||
let aab_outputs = if options.aab {
|
||||
aab::build(
|
||||
config,
|
||||
env,
|
||||
|
||||
@ -10,8 +10,8 @@ use crate::{
|
||||
dev::Options as DevOptions,
|
||||
error::{Context, ErrorExt},
|
||||
helpers::{
|
||||
app_paths::tauri_dir,
|
||||
config::{get as get_tauri_config, ConfigHandle},
|
||||
app_paths::Dirs,
|
||||
config::{get_config as get_tauri_config, ConfigMetadata},
|
||||
flock,
|
||||
},
|
||||
interface::{AppInterface, Interface, MobileOptions, Options as InterfaceOptions},
|
||||
@ -45,7 +45,7 @@ use std::{env::set_current_dir, net::Ipv4Addr, path::PathBuf};
|
||||
pub struct Options {
|
||||
/// List of cargo features to activate
|
||||
#[clap(short, long, action = ArgAction::Append, num_args(0..))]
|
||||
pub features: Option<Vec<String>>,
|
||||
pub features: Vec<String>,
|
||||
/// Exit on panic
|
||||
#[clap(short, long)]
|
||||
exit_on_panic: bool,
|
||||
@ -131,16 +131,16 @@ impl From<Options> for DevOptions {
|
||||
}
|
||||
|
||||
pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> {
|
||||
crate::helpers::app_paths::resolve();
|
||||
let dirs = crate::helpers::app_paths::resolve_dirs();
|
||||
|
||||
let result = run_command(options, noise_level);
|
||||
let result = run_command(options, noise_level, dirs);
|
||||
if result.is_err() {
|
||||
crate::dev::kill_before_dev_process();
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn run_command(options: Options, noise_level: NoiseLevel) -> Result<()> {
|
||||
fn run_command(options: Options, noise_level: NoiseLevel, dirs: Dirs) -> Result<()> {
|
||||
delete_codegen_vars();
|
||||
// setup env additions before calling env()
|
||||
if let Some(root_certificate_path) = &options.root_certificate_path {
|
||||
@ -160,6 +160,7 @@ fn run_command(options: Options, noise_level: NoiseLevel) -> Result<()> {
|
||||
.iter()
|
||||
.map(|conf| &conf.0)
|
||||
.collect::<Vec<_>>(),
|
||||
dirs.tauri,
|
||||
)?;
|
||||
|
||||
let env = env(false)?;
|
||||
@ -183,23 +184,19 @@ fn run_command(options: Options, noise_level: NoiseLevel) -> Result<()> {
|
||||
dev_options.target = Some(target_triple);
|
||||
|
||||
let (interface, config, metadata) = {
|
||||
let tauri_config_guard = tauri_config.lock().unwrap();
|
||||
let tauri_config_ = tauri_config_guard.as_ref().unwrap();
|
||||
let interface = AppInterface::new(&tauri_config, dev_options.target.clone(), dirs.tauri)?;
|
||||
|
||||
let interface = AppInterface::new(tauri_config_, dev_options.target.clone())?;
|
||||
|
||||
let app = get_app(MobileTarget::Android, tauri_config_, &interface);
|
||||
let app = get_app(MobileTarget::Android, &tauri_config, &interface, dirs.tauri);
|
||||
let (config, metadata) = get_config(
|
||||
&app,
|
||||
tauri_config_,
|
||||
&tauri_config,
|
||||
dev_options.features.as_ref(),
|
||||
&Default::default(),
|
||||
);
|
||||
(interface, config, metadata)
|
||||
};
|
||||
|
||||
let tauri_path = tauri_dir();
|
||||
set_current_dir(tauri_path).context("failed to set current directory to Tauri directory")?;
|
||||
set_current_dir(dirs.tauri).context("failed to set current directory to Tauri directory")?;
|
||||
|
||||
ensure_init(
|
||||
&tauri_config,
|
||||
@ -218,6 +215,7 @@ fn run_command(options: Options, noise_level: NoiseLevel) -> Result<()> {
|
||||
&config,
|
||||
&metadata,
|
||||
noise_level,
|
||||
&dirs,
|
||||
)
|
||||
}
|
||||
|
||||
@ -226,12 +224,13 @@ fn run_dev(
|
||||
mut interface: AppInterface,
|
||||
options: Options,
|
||||
mut dev_options: DevOptions,
|
||||
tauri_config: ConfigHandle,
|
||||
mut tauri_config: ConfigMetadata,
|
||||
device: Option<Device>,
|
||||
mut env: Env,
|
||||
config: &AndroidConfig,
|
||||
metadata: &AndroidMetadata,
|
||||
noise_level: NoiseLevel,
|
||||
dirs: &Dirs,
|
||||
) -> Result<()> {
|
||||
// when --host is provided or running on a physical device or resolving 0.0.0.0 we must use the network IP
|
||||
if options.host.0.is_some()
|
||||
@ -239,25 +238,22 @@ fn run_dev(
|
||||
.as_ref()
|
||||
.map(|device| !device.serial_no().starts_with("emulator"))
|
||||
.unwrap_or(false)
|
||||
|| tauri_config
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.build
|
||||
.dev_url
|
||||
.as_ref()
|
||||
.is_some_and(|url| {
|
||||
matches!(
|
||||
url.host(),
|
||||
Some(Host::Ipv4(i)) if i == Ipv4Addr::UNSPECIFIED
|
||||
)
|
||||
})
|
||||
|| tauri_config.build.dev_url.as_ref().is_some_and(|url| {
|
||||
matches!(
|
||||
url.host(),
|
||||
Some(Host::Ipv4(i)) if i == Ipv4Addr::UNSPECIFIED
|
||||
)
|
||||
})
|
||||
{
|
||||
use_network_address_for_dev_url(&tauri_config, &mut dev_options, options.force_ip_prompt)?;
|
||||
use_network_address_for_dev_url(
|
||||
&mut tauri_config,
|
||||
&mut dev_options,
|
||||
options.force_ip_prompt,
|
||||
dirs.tauri,
|
||||
)?;
|
||||
}
|
||||
|
||||
crate::dev::setup(&interface, &mut dev_options, tauri_config)?;
|
||||
crate::dev::setup(&interface, &mut dev_options, &mut tauri_config, dirs)?;
|
||||
|
||||
let interface_options = InterfaceOptions {
|
||||
debug: !dev_options.release_mode,
|
||||
@ -266,12 +262,12 @@ fn run_dev(
|
||||
};
|
||||
|
||||
let app_settings = interface.app_settings();
|
||||
let out_dir = app_settings.out_dir(&interface_options)?;
|
||||
let out_dir = app_settings.out_dir(&interface_options, dirs.tauri)?;
|
||||
let _lock = flock::open_rw(out_dir.join("lock").with_extension("android"), "Android")?;
|
||||
|
||||
configure_cargo(&mut env, config)?;
|
||||
|
||||
generate_tauri_properties(config, tauri_config.lock().unwrap().as_ref().unwrap(), true)?;
|
||||
generate_tauri_properties(config, &tauri_config, true)?;
|
||||
|
||||
let installed_targets =
|
||||
crate::interface::rust::installation::installed_targets().unwrap_or_default();
|
||||
@ -307,6 +303,7 @@ fn run_dev(
|
||||
|
||||
let open = options.open;
|
||||
interface.mobile_dev(
|
||||
&mut tauri_config,
|
||||
MobileOptions {
|
||||
debug: !options.release_mode,
|
||||
features: options.features,
|
||||
@ -315,7 +312,7 @@ fn run_dev(
|
||||
no_watch: options.no_watch,
|
||||
additional_watch_folders: options.additional_watch_folders,
|
||||
},
|
||||
|options| {
|
||||
|options, tauri_config| {
|
||||
let cli_options = CliOptions {
|
||||
dev: true,
|
||||
features: options.features.clone(),
|
||||
@ -329,9 +326,9 @@ fn run_dev(
|
||||
}),
|
||||
};
|
||||
|
||||
let _handle = write_options(tauri_config.lock().unwrap().as_ref().unwrap(), cli_options)?;
|
||||
let _handle = write_options(tauri_config, cli_options)?;
|
||||
|
||||
inject_resources(config, tauri_config.lock().unwrap().as_ref().unwrap())?;
|
||||
inject_resources(config, tauri_config)?;
|
||||
|
||||
if open {
|
||||
open_and_wait(config, &env)
|
||||
@ -347,6 +344,7 @@ fn run_dev(
|
||||
open_and_wait(config, &env)
|
||||
}
|
||||
},
|
||||
dirs,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -104,18 +104,17 @@ enum Commands {
|
||||
}
|
||||
|
||||
pub fn command(cli: Cli, verbosity: u8) -> Result<()> {
|
||||
let dirs = crate::helpers::app_paths::resolve_dirs();
|
||||
let noise_level = NoiseLevel::from_occurrences(verbosity as u64);
|
||||
match cli.command {
|
||||
Commands::Init(options) => {
|
||||
crate::helpers::app_paths::resolve();
|
||||
init_command(
|
||||
MobileTarget::Android,
|
||||
options.ci,
|
||||
false,
|
||||
options.skip_targets_install,
|
||||
options.config,
|
||||
)?
|
||||
}
|
||||
Commands::Init(options) => init_command(
|
||||
MobileTarget::Android,
|
||||
options.ci,
|
||||
false,
|
||||
options.skip_targets_install,
|
||||
options.config,
|
||||
&dirs,
|
||||
)?,
|
||||
Commands::Dev(options) => dev::command(options, noise_level)?,
|
||||
Commands::Build(options) => build::command(options, noise_level).map(|_| ())?,
|
||||
Commands::Run(options) => run::command(options, noise_level)?,
|
||||
@ -128,19 +127,14 @@ pub fn command(cli: Cli, verbosity: u8) -> Result<()> {
|
||||
pub fn get_config(
|
||||
app: &App,
|
||||
config: &TauriConfig,
|
||||
features: Option<&Vec<String>>,
|
||||
features: &[String],
|
||||
cli_options: &CliOptions,
|
||||
) -> (AndroidConfig, AndroidMetadata) {
|
||||
let mut android_options = cli_options.clone();
|
||||
if let Some(features) = features {
|
||||
android_options
|
||||
.features
|
||||
.get_or_insert(Vec::new())
|
||||
.extend_from_slice(features);
|
||||
}
|
||||
android_options.features.extend_from_slice(features);
|
||||
|
||||
let raw = RawAndroidConfig {
|
||||
features: android_options.features.clone(),
|
||||
features: Some(android_options.features.clone()),
|
||||
logcat_filter_specs: vec![
|
||||
"RustStdoutStderr".into(),
|
||||
format!(
|
||||
@ -161,7 +155,7 @@ pub fn get_config(
|
||||
let metadata = AndroidMetadata {
|
||||
supported: true,
|
||||
cargo_args: Some(android_options.args),
|
||||
features: android_options.features,
|
||||
features: Some(android_options.features),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
@ -257,8 +251,8 @@ fn ensure_java() -> Result<()> {
|
||||
|
||||
fn ensure_sdk(non_interactive: bool) -> Result<()> {
|
||||
let android_home = std::env::var_os("ANDROID_HOME")
|
||||
.map(PathBuf::from)
|
||||
.or_else(|| std::env::var_os("ANDROID_SDK_ROOT").map(PathBuf::from));
|
||||
.or_else(|| std::env::var_os("ANDROID_SDK_ROOT"))
|
||||
.map(PathBuf::from);
|
||||
if !android_home.as_ref().is_some_and(|v| v.exists()) {
|
||||
log::info!(
|
||||
"ANDROID_HOME {}, trying to locate Android SDK...",
|
||||
@ -354,8 +348,8 @@ fn ensure_sdk(non_interactive: bool) -> Result<()> {
|
||||
fn ensure_ndk(non_interactive: bool) -> Result<()> {
|
||||
// re-evaluate ANDROID_HOME
|
||||
let android_home = std::env::var_os("ANDROID_HOME")
|
||||
.or_else(|| std::env::var_os("ANDROID_SDK_ROOT"))
|
||||
.map(PathBuf::from)
|
||||
.or_else(|| std::env::var_os("ANDROID_SDK_ROOT").map(PathBuf::from))
|
||||
.context("Failed to locate Android SDK")?;
|
||||
let mut installed_ndks = read_dir(android_home.join("ndk"))
|
||||
.map(|dir| {
|
||||
|
||||
@ -13,6 +13,7 @@ use std::path::PathBuf;
|
||||
use super::{configure_cargo, device_prompt, env};
|
||||
use crate::{
|
||||
error::Context,
|
||||
helpers::config::ConfigMetadata,
|
||||
interface::{DevProcess, Interface, WatcherOptions},
|
||||
mobile::{DevChild, TargetDevice},
|
||||
ConfigValue, Result,
|
||||
@ -29,7 +30,7 @@ pub struct Options {
|
||||
pub release: bool,
|
||||
/// List of cargo features to activate
|
||||
#[clap(short, long, action = ArgAction::Append, num_args(0..))]
|
||||
pub features: Option<Vec<String>>,
|
||||
pub features: Vec<String>,
|
||||
/// JSON strings or paths to JSON, JSON5 or TOML files to merge with the default configuration file
|
||||
///
|
||||
/// Configurations are merged in the order they are provided, which means a particular value overwrites previous values when a config key-value pair conflicts.
|
||||
@ -77,7 +78,17 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> {
|
||||
}
|
||||
};
|
||||
|
||||
let mut built_application = super::build::command(
|
||||
let dirs = crate::helpers::app_paths::resolve_dirs();
|
||||
let mut tauri_config = crate::helpers::config::get_config(
|
||||
tauri_utils::platform::Target::Android,
|
||||
&options
|
||||
.config
|
||||
.iter()
|
||||
.map(|conf| &conf.0)
|
||||
.collect::<Vec<_>>(),
|
||||
dirs.tauri,
|
||||
)?;
|
||||
let mut built_application = super::build::run(
|
||||
super::build::Options {
|
||||
debug: !options.release,
|
||||
targets: device.as_ref().map(|d| {
|
||||
@ -90,8 +101,9 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> {
|
||||
features: options.features,
|
||||
config: options.config.clone(),
|
||||
split_per_abi: true,
|
||||
apk: Some(false),
|
||||
aab: Some(false),
|
||||
apk: false,
|
||||
aab: false,
|
||||
skip_bundle: false,
|
||||
open: options.open,
|
||||
ci: false,
|
||||
args: options.args,
|
||||
@ -102,6 +114,8 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> {
|
||||
}),
|
||||
},
|
||||
noise_level,
|
||||
&dirs,
|
||||
&tauri_config,
|
||||
)?;
|
||||
|
||||
configure_cargo(&mut env, &built_application.config)?;
|
||||
@ -111,7 +125,7 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> {
|
||||
if let Some(device) = device {
|
||||
let config = built_application.config.clone();
|
||||
let release = options.release;
|
||||
let runner = move || {
|
||||
let runner = move |_tauri_config: &ConfigMetadata| {
|
||||
device
|
||||
.run(
|
||||
&config,
|
||||
@ -136,14 +150,16 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> {
|
||||
};
|
||||
|
||||
if options.no_watch {
|
||||
runner()?;
|
||||
runner(&tauri_config)?;
|
||||
} else {
|
||||
built_application.interface.watch(
|
||||
&mut tauri_config,
|
||||
WatcherOptions {
|
||||
config: options.config,
|
||||
additional_watch_folders: options.additional_watch_folders,
|
||||
},
|
||||
runner,
|
||||
&dirs,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,8 @@
|
||||
|
||||
use super::{get_app, Target};
|
||||
use crate::{
|
||||
helpers::{config::get as get_tauri_config, template::JsonMap},
|
||||
helpers::app_paths::Dirs,
|
||||
helpers::{config::get_config as get_tauri_config, template::JsonMap},
|
||||
interface::{AppInterface, Interface},
|
||||
ConfigValue, Result,
|
||||
};
|
||||
@ -28,6 +29,7 @@ pub fn command(
|
||||
reinstall_deps: bool,
|
||||
skip_targets_install: bool,
|
||||
config: Vec<ConfigValue>,
|
||||
dirs: &Dirs,
|
||||
) -> Result<()> {
|
||||
let wrapper = TextWrapper::default();
|
||||
|
||||
@ -38,6 +40,7 @@ pub fn command(
|
||||
reinstall_deps,
|
||||
skip_targets_install,
|
||||
config,
|
||||
dirs,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
@ -49,19 +52,19 @@ pub fn exec(
|
||||
#[allow(unused_variables)] reinstall_deps: bool,
|
||||
skip_targets_install: bool,
|
||||
config: Vec<ConfigValue>,
|
||||
dirs: &Dirs,
|
||||
) -> Result<App> {
|
||||
let tauri_config = get_tauri_config(
|
||||
target.platform_target(),
|
||||
&config.iter().map(|conf| &conf.0).collect::<Vec<_>>(),
|
||||
dirs.tauri,
|
||||
)?;
|
||||
|
||||
let tauri_config_guard = tauri_config.lock().unwrap();
|
||||
let tauri_config_ = tauri_config_guard.as_ref().unwrap();
|
||||
|
||||
let app = get_app(
|
||||
target,
|
||||
tauri_config_,
|
||||
&AppInterface::new(tauri_config_, None)?,
|
||||
&tauri_config,
|
||||
&AppInterface::new(&tauri_config, None, dirs.tauri)?,
|
||||
dirs.tauri,
|
||||
);
|
||||
|
||||
let (handlebars, mut map) = handlebars(&app);
|
||||
@ -135,7 +138,7 @@ pub fn exec(
|
||||
Target::Android => {
|
||||
let _env = super::android::env(non_interactive)?;
|
||||
let (config, metadata) =
|
||||
super::android::get_config(&app, tauri_config_, None, &Default::default());
|
||||
super::android::get_config(&app, &tauri_config, &[], &Default::default());
|
||||
map.insert("android", &config);
|
||||
super::android::project::gen(
|
||||
&config,
|
||||
@ -150,10 +153,10 @@ pub fn exec(
|
||||
// Generate Xcode project
|
||||
Target::Ios => {
|
||||
let (config, metadata) =
|
||||
super::ios::get_config(&app, tauri_config_, None, &Default::default())?;
|
||||
super::ios::get_config(&app, &tauri_config, &[], &Default::default(), dirs.tauri)?;
|
||||
map.insert("apple", &config);
|
||||
super::ios::project::gen(
|
||||
tauri_config_,
|
||||
&tauri_config,
|
||||
&config,
|
||||
&metadata,
|
||||
(handlebars, map),
|
||||
|
||||
@ -11,8 +11,8 @@ use crate::{
|
||||
build::Options as BuildOptions,
|
||||
error::{Context, ErrorExt},
|
||||
helpers::{
|
||||
app_paths::tauri_dir,
|
||||
config::{get as get_tauri_config, ConfigHandle},
|
||||
app_paths::Dirs,
|
||||
config::{get_config as get_tauri_config, ConfigMetadata},
|
||||
flock,
|
||||
plist::merge_plist,
|
||||
},
|
||||
@ -60,7 +60,7 @@ pub struct Options {
|
||||
pub targets: Option<Vec<String>>,
|
||||
/// List of cargo features to activate
|
||||
#[clap(short, long, action = ArgAction::Append, num_args(0..))]
|
||||
pub features: Option<Vec<String>>,
|
||||
pub features: Vec<String>,
|
||||
/// JSON strings or paths to JSON, JSON5 or TOML files to merge with the default configuration file
|
||||
///
|
||||
/// Configurations are merged in the order they are provided, which means a particular value overwrites previous values when a config key-value pair conflicts.
|
||||
@ -169,9 +169,7 @@ pub struct BuiltApplication {
|
||||
export_options_tmp: Option<tempfile::NamedTempFile>,
|
||||
}
|
||||
|
||||
pub fn command(options: Options, noise_level: NoiseLevel) -> Result<BuiltApplication> {
|
||||
crate::helpers::app_paths::resolve();
|
||||
|
||||
pub fn command(options: Options, noise_level: NoiseLevel, dirs: &Dirs) -> Result<BuiltApplication> {
|
||||
let mut build_options: BuildOptions = options.clone().into();
|
||||
build_options.target = Some(
|
||||
Target::all()
|
||||
@ -191,26 +189,24 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<BuiltApplica
|
||||
let tauri_config = get_tauri_config(
|
||||
tauri_utils::platform::Target::Ios,
|
||||
&options.config.iter().map(|c| &c.0).collect::<Vec<_>>(),
|
||||
dirs.tauri,
|
||||
)?;
|
||||
let (interface, mut config) = {
|
||||
let tauri_config_guard = tauri_config.lock().unwrap();
|
||||
let tauri_config_ = tauri_config_guard.as_ref().unwrap();
|
||||
|
||||
let interface = AppInterface::new(tauri_config_, build_options.target.clone())?;
|
||||
let interface = AppInterface::new(&tauri_config, build_options.target.clone(), dirs.tauri)?;
|
||||
interface.build_options(&mut Vec::new(), &mut build_options.features, true);
|
||||
|
||||
let app = get_app(MobileTarget::Ios, tauri_config_, &interface);
|
||||
let app = get_app(MobileTarget::Ios, &tauri_config, &interface, dirs.tauri);
|
||||
let (config, _metadata) = get_config(
|
||||
&app,
|
||||
tauri_config_,
|
||||
build_options.features.as_ref(),
|
||||
&tauri_config,
|
||||
&build_options.features,
|
||||
&Default::default(),
|
||||
dirs.tauri,
|
||||
)?;
|
||||
(interface, config)
|
||||
};
|
||||
|
||||
let tauri_path = tauri_dir();
|
||||
set_current_dir(tauri_path).context("failed to set current directory")?;
|
||||
set_current_dir(dirs.tauri).context("failed to set current directory")?;
|
||||
|
||||
ensure_init(
|
||||
&tauri_config,
|
||||
@ -219,7 +215,7 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<BuiltApplica
|
||||
MobileTarget::Ios,
|
||||
options.ci,
|
||||
)?;
|
||||
inject_resources(&config, tauri_config.lock().unwrap().as_ref().unwrap())?;
|
||||
inject_resources(&config, &tauri_config)?;
|
||||
|
||||
let mut plist = plist::Dictionary::new();
|
||||
plist.insert(
|
||||
@ -233,21 +229,13 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<BuiltApplica
|
||||
.join("Info.plist");
|
||||
let mut src_plists = vec![info_plist_path.clone().into()];
|
||||
src_plists.push(plist::Value::Dictionary(plist).into());
|
||||
if tauri_path.join("Info.plist").exists() {
|
||||
src_plists.push(tauri_path.join("Info.plist").into());
|
||||
if dirs.tauri.join("Info.plist").exists() {
|
||||
src_plists.push(dirs.tauri.join("Info.plist").into());
|
||||
}
|
||||
if tauri_path.join("Info.ios.plist").exists() {
|
||||
src_plists.push(tauri_path.join("Info.ios.plist").into());
|
||||
if dirs.tauri.join("Info.ios.plist").exists() {
|
||||
src_plists.push(dirs.tauri.join("Info.ios.plist").into());
|
||||
}
|
||||
if let Some(info_plist) = &tauri_config
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.bundle
|
||||
.ios
|
||||
.info_plist
|
||||
{
|
||||
if let Some(info_plist) = &tauri_config.bundle.ios.info_plist {
|
||||
src_plists.push(info_plist.clone().into());
|
||||
}
|
||||
let merged_info_plist = merge_plist(src_plists)?;
|
||||
@ -340,6 +328,7 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<BuiltApplica
|
||||
&mut config,
|
||||
&mut env,
|
||||
noise_level,
|
||||
&dirs,
|
||||
)?;
|
||||
|
||||
if open {
|
||||
@ -359,10 +348,11 @@ fn run_build(
|
||||
interface: &AppInterface,
|
||||
options: Options,
|
||||
mut build_options: BuildOptions,
|
||||
tauri_config: ConfigHandle,
|
||||
tauri_config: ConfigMetadata,
|
||||
config: &mut AppleConfig,
|
||||
env: &mut Env,
|
||||
noise_level: NoiseLevel,
|
||||
dirs: &Dirs,
|
||||
) -> Result<OptionsHandle> {
|
||||
let profile = if options.debug {
|
||||
Profile::Debug
|
||||
@ -370,20 +360,18 @@ fn run_build(
|
||||
Profile::Release
|
||||
};
|
||||
|
||||
crate::build::setup(
|
||||
interface,
|
||||
&mut build_options,
|
||||
tauri_config.lock().unwrap().as_ref().unwrap(),
|
||||
true,
|
||||
)?;
|
||||
crate::build::setup(interface, &mut build_options, &tauri_config, dirs, true)?;
|
||||
|
||||
let app_settings = interface.app_settings();
|
||||
let out_dir = app_settings.out_dir(&InterfaceOptions {
|
||||
debug: build_options.debug,
|
||||
target: build_options.target.clone(),
|
||||
args: build_options.args.clone(),
|
||||
..Default::default()
|
||||
})?;
|
||||
let out_dir = app_settings.out_dir(
|
||||
&InterfaceOptions {
|
||||
debug: build_options.debug,
|
||||
target: build_options.target.clone(),
|
||||
args: build_options.args.clone(),
|
||||
..Default::default()
|
||||
},
|
||||
dirs.tauri,
|
||||
)?;
|
||||
let _lock = flock::open_rw(out_dir.join("lock").with_extension("ios"), "iOS")?;
|
||||
|
||||
let cli_options = CliOptions {
|
||||
@ -395,7 +383,7 @@ fn run_build(
|
||||
config: build_options.config.clone(),
|
||||
target_device: options.target_device.clone(),
|
||||
};
|
||||
let handle = write_options(tauri_config.lock().unwrap().as_ref().unwrap(), cli_options)?;
|
||||
let handle = write_options(&tauri_config, cli_options)?;
|
||||
|
||||
if options.open {
|
||||
return Ok(handle);
|
||||
|
||||
@ -10,8 +10,8 @@ use crate::{
|
||||
dev::Options as DevOptions,
|
||||
error::{Context, ErrorExt},
|
||||
helpers::{
|
||||
app_paths::tauri_dir,
|
||||
config::{get as get_tauri_config, ConfigHandle},
|
||||
app_paths::Dirs,
|
||||
config::{get_config as get_tauri_config, ConfigMetadata},
|
||||
flock,
|
||||
plist::merge_plist,
|
||||
},
|
||||
@ -54,7 +54,7 @@ environment variable to determine whether the public network should be used or n
|
||||
pub struct Options {
|
||||
/// List of cargo features to activate
|
||||
#[clap(short, long, action = ArgAction::Append, num_args(0..))]
|
||||
pub features: Option<Vec<String>>,
|
||||
pub features: Vec<String>,
|
||||
/// Exit on panic
|
||||
#[clap(short, long)]
|
||||
exit_on_panic: bool,
|
||||
@ -138,16 +138,16 @@ impl From<Options> for DevOptions {
|
||||
}
|
||||
|
||||
pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> {
|
||||
crate::helpers::app_paths::resolve();
|
||||
let dirs = crate::helpers::app_paths::resolve_dirs();
|
||||
|
||||
let result = run_command(options, noise_level);
|
||||
let result = run_command(options, noise_level, dirs);
|
||||
if result.is_err() {
|
||||
crate::dev::kill_before_dev_process();
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn run_command(options: Options, noise_level: NoiseLevel) -> Result<()> {
|
||||
fn run_command(options: Options, noise_level: NoiseLevel, dirs: Dirs) -> Result<()> {
|
||||
// setup env additions before calling env()
|
||||
if let Some(root_certificate_path) = &options.root_certificate_path {
|
||||
std::env::set_var(
|
||||
@ -186,26 +186,24 @@ fn run_command(options: Options, noise_level: NoiseLevel) -> Result<()> {
|
||||
let tauri_config = get_tauri_config(
|
||||
tauri_utils::platform::Target::Ios,
|
||||
&options.config.iter().map(|c| &c.0).collect::<Vec<_>>(),
|
||||
dirs.tauri,
|
||||
)?;
|
||||
let (interface, config) = {
|
||||
let tauri_config_guard = tauri_config.lock().unwrap();
|
||||
let tauri_config_ = tauri_config_guard.as_ref().unwrap();
|
||||
let interface = AppInterface::new(&tauri_config, Some(target_triple), dirs.tauri)?;
|
||||
|
||||
let interface = AppInterface::new(tauri_config_, Some(target_triple))?;
|
||||
|
||||
let app = get_app(MobileTarget::Ios, tauri_config_, &interface);
|
||||
let app = get_app(MobileTarget::Ios, &tauri_config, &interface, dirs.tauri);
|
||||
let (config, _metadata) = get_config(
|
||||
&app,
|
||||
tauri_config_,
|
||||
dev_options.features.as_ref(),
|
||||
&tauri_config,
|
||||
&dev_options.features,
|
||||
&Default::default(),
|
||||
dirs.tauri,
|
||||
)?;
|
||||
|
||||
(interface, config)
|
||||
};
|
||||
|
||||
let tauri_path = tauri_dir();
|
||||
set_current_dir(tauri_path).context("failed to set current directory to Tauri directory")?;
|
||||
set_current_dir(dirs.tauri).context("failed to set current directory to Tauri directory")?;
|
||||
|
||||
ensure_init(
|
||||
&tauri_config,
|
||||
@ -214,28 +212,20 @@ fn run_command(options: Options, noise_level: NoiseLevel) -> Result<()> {
|
||||
MobileTarget::Ios,
|
||||
false,
|
||||
)?;
|
||||
inject_resources(&config, tauri_config.lock().unwrap().as_ref().unwrap())?;
|
||||
inject_resources(&config, &tauri_config)?;
|
||||
|
||||
let info_plist_path = config
|
||||
.project_dir()
|
||||
.join(config.scheme())
|
||||
.join("Info.plist");
|
||||
let mut src_plists = vec![info_plist_path.clone().into()];
|
||||
if tauri_path.join("Info.plist").exists() {
|
||||
src_plists.push(tauri_path.join("Info.plist").into());
|
||||
if dirs.tauri.join("Info.plist").exists() {
|
||||
src_plists.push(dirs.tauri.join("Info.plist").into());
|
||||
}
|
||||
if tauri_path.join("Info.ios.plist").exists() {
|
||||
src_plists.push(tauri_path.join("Info.ios.plist").into());
|
||||
if dirs.tauri.join("Info.ios.plist").exists() {
|
||||
src_plists.push(dirs.tauri.join("Info.ios.plist").into());
|
||||
}
|
||||
if let Some(info_plist) = &tauri_config
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.bundle
|
||||
.ios
|
||||
.info_plist
|
||||
{
|
||||
if let Some(info_plist) = &tauri_config.bundle.ios.info_plist {
|
||||
src_plists.push(info_plist.clone().into());
|
||||
}
|
||||
let merged_info_plist = merge_plist(src_plists)?;
|
||||
@ -274,6 +264,7 @@ fn run_command(options: Options, noise_level: NoiseLevel) -> Result<()> {
|
||||
env,
|
||||
&config,
|
||||
noise_level,
|
||||
&dirs,
|
||||
)
|
||||
}
|
||||
|
||||
@ -282,11 +273,12 @@ fn run_dev(
|
||||
mut interface: AppInterface,
|
||||
options: Options,
|
||||
mut dev_options: DevOptions,
|
||||
tauri_config: ConfigHandle,
|
||||
mut tauri_config: ConfigMetadata,
|
||||
device: Option<Device>,
|
||||
env: Env,
|
||||
config: &AppleConfig,
|
||||
noise_level: NoiseLevel,
|
||||
dirs: &Dirs,
|
||||
) -> Result<()> {
|
||||
// when --host is provided or running on a physical device or resolving 0.0.0.0 we must use the network IP
|
||||
if options.host.0.is_some()
|
||||
@ -294,38 +286,39 @@ fn run_dev(
|
||||
.as_ref()
|
||||
.map(|device| !matches!(device.kind(), DeviceKind::Simulator))
|
||||
.unwrap_or(false)
|
||||
|| tauri_config
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.build
|
||||
.dev_url
|
||||
.as_ref()
|
||||
.is_some_and(|url| {
|
||||
matches!(
|
||||
|| tauri_config.build.dev_url.as_ref().is_some_and(|url| {
|
||||
matches!(
|
||||
url.host(),
|
||||
Some(Host::Ipv4(i)) if i == Ipv4Addr::UNSPECIFIED
|
||||
)
|
||||
})
|
||||
)
|
||||
})
|
||||
{
|
||||
use_network_address_for_dev_url(&tauri_config, &mut dev_options, options.force_ip_prompt)?;
|
||||
use_network_address_for_dev_url(
|
||||
&mut tauri_config,
|
||||
&mut dev_options,
|
||||
options.force_ip_prompt,
|
||||
dirs.tauri,
|
||||
)?;
|
||||
}
|
||||
|
||||
crate::dev::setup(&interface, &mut dev_options, tauri_config.clone())?;
|
||||
crate::dev::setup(&interface, &mut dev_options, &mut tauri_config, &dirs)?;
|
||||
|
||||
let app_settings = interface.app_settings();
|
||||
let out_dir = app_settings.out_dir(&InterfaceOptions {
|
||||
debug: !dev_options.release_mode,
|
||||
target: dev_options.target.clone(),
|
||||
..Default::default()
|
||||
})?;
|
||||
let out_dir = app_settings.out_dir(
|
||||
&InterfaceOptions {
|
||||
debug: !dev_options.release_mode,
|
||||
target: dev_options.target.clone(),
|
||||
..Default::default()
|
||||
},
|
||||
dirs.tauri,
|
||||
)?;
|
||||
let _lock = flock::open_rw(out_dir.join("lock").with_extension("ios"), "iOS")?;
|
||||
|
||||
let set_host = options.host.0.is_some();
|
||||
|
||||
let open = options.open;
|
||||
interface.mobile_dev(
|
||||
&mut tauri_config,
|
||||
MobileOptions {
|
||||
debug: true,
|
||||
features: options.features,
|
||||
@ -334,7 +327,7 @@ fn run_dev(
|
||||
no_watch: options.no_watch,
|
||||
additional_watch_folders: options.additional_watch_folders,
|
||||
},
|
||||
|options| {
|
||||
|options, tauri_config| {
|
||||
let cli_options = CliOptions {
|
||||
dev: true,
|
||||
features: options.features.clone(),
|
||||
@ -344,7 +337,7 @@ fn run_dev(
|
||||
config: dev_options.config.clone(),
|
||||
target_device: None,
|
||||
};
|
||||
let _handle = write_options(tauri_config.lock().unwrap().as_ref().unwrap(), cli_options)?;
|
||||
let _handle = write_options(tauri_config, cli_options)?;
|
||||
|
||||
let open_xcode = || {
|
||||
if !set_host {
|
||||
@ -371,6 +364,7 @@ fn run_dev(
|
||||
open_xcode()
|
||||
}
|
||||
},
|
||||
&dirs,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -30,8 +30,7 @@ use super::{
|
||||
use crate::{
|
||||
error::{Context, ErrorExt},
|
||||
helpers::{
|
||||
app_paths::tauri_dir,
|
||||
config::{BundleResources, Config as TauriConfig, ConfigHandle},
|
||||
config::{BundleResources, Config as TauriConfig, ConfigMetadata},
|
||||
pbxproj, strip_semver_prerelease_tag,
|
||||
},
|
||||
ConfigValue, Error, Result,
|
||||
@ -40,7 +39,7 @@ use crate::{
|
||||
use std::{
|
||||
env::{set_var, var_os},
|
||||
fs::create_dir_all,
|
||||
path::PathBuf,
|
||||
path::Path,
|
||||
str::FromStr,
|
||||
thread::sleep,
|
||||
time::Duration,
|
||||
@ -103,19 +102,18 @@ enum Commands {
|
||||
|
||||
pub fn command(cli: Cli, verbosity: u8) -> Result<()> {
|
||||
let noise_level = NoiseLevel::from_occurrences(verbosity as u64);
|
||||
let dirs = crate::helpers::app_paths::resolve_dirs();
|
||||
match cli.command {
|
||||
Commands::Init(options) => {
|
||||
crate::helpers::app_paths::resolve();
|
||||
init_command(
|
||||
MobileTarget::Ios,
|
||||
options.ci,
|
||||
options.reinstall_deps,
|
||||
options.skip_targets_install,
|
||||
options.config,
|
||||
)?
|
||||
}
|
||||
Commands::Init(options) => init_command(
|
||||
MobileTarget::Ios,
|
||||
options.ci,
|
||||
options.reinstall_deps,
|
||||
options.skip_targets_install,
|
||||
options.config,
|
||||
&dirs,
|
||||
)?,
|
||||
Commands::Dev(options) => dev::command(options, noise_level)?,
|
||||
Commands::Build(options) => build::command(options, noise_level).map(|_| ())?,
|
||||
Commands::Build(options) => build::command(options, noise_level, &dirs).map(|_| ())?,
|
||||
Commands::Run(options) => run::command(options, noise_level)?,
|
||||
Commands::XcodeScript(options) => xcode_script::command(options)?,
|
||||
}
|
||||
@ -126,16 +124,12 @@ pub fn command(cli: Cli, verbosity: u8) -> Result<()> {
|
||||
pub fn get_config(
|
||||
app: &App,
|
||||
tauri_config: &TauriConfig,
|
||||
features: Option<&Vec<String>>,
|
||||
features: &[String],
|
||||
cli_options: &CliOptions,
|
||||
tauri_dir: &Path,
|
||||
) -> Result<(AppleConfig, AppleMetadata)> {
|
||||
let mut ios_options = cli_options.clone();
|
||||
if let Some(features) = features {
|
||||
ios_options
|
||||
.features
|
||||
.get_or_insert(Vec::new())
|
||||
.extend_from_slice(features);
|
||||
}
|
||||
ios_options.features.extend_from_slice(features);
|
||||
|
||||
let bundle_version = if let Some(bundle_version) = tauri_config
|
||||
.bundle
|
||||
@ -232,7 +226,7 @@ pub fn get_config(
|
||||
}
|
||||
}
|
||||
}),
|
||||
ios_features: ios_options.features.clone(),
|
||||
ios_features: Some(ios_options.features.clone()),
|
||||
bundle_version,
|
||||
bundle_version_short,
|
||||
ios_version: Some(tauri_config.bundle.ios.minimum_system_version.clone()),
|
||||
@ -241,8 +235,6 @@ pub fn get_config(
|
||||
let config = AppleConfig::from_raw(app.clone(), Some(raw))
|
||||
.context("failed to create Apple configuration")?;
|
||||
|
||||
let tauri_dir = tauri_dir();
|
||||
|
||||
let mut vendor_frameworks = Vec::new();
|
||||
let mut frameworks = Vec::new();
|
||||
for framework in tauri_config
|
||||
@ -252,7 +244,7 @@ pub fn get_config(
|
||||
.clone()
|
||||
.unwrap_or_default()
|
||||
{
|
||||
let framework_path = PathBuf::from(&framework);
|
||||
let framework_path = Path::new(&framework);
|
||||
let ext = framework_path.extension().unwrap_or_default();
|
||||
if ext.is_empty() {
|
||||
frameworks.push(framework);
|
||||
@ -277,7 +269,7 @@ pub fn get_config(
|
||||
supported: true,
|
||||
ios: ApplePlatform {
|
||||
cargo_args: Some(ios_options.args),
|
||||
features: ios_options.features,
|
||||
features: Some(ios_options.features),
|
||||
frameworks: Some(frameworks),
|
||||
vendor_frameworks: Some(vendor_frameworks),
|
||||
..Default::default()
|
||||
@ -554,26 +546,14 @@ pub fn load_pbxproj(config: &AppleConfig) -> Result<pbxproj::Pbxproj> {
|
||||
|
||||
pub fn synchronize_project_config(
|
||||
config: &AppleConfig,
|
||||
tauri_config: &ConfigHandle,
|
||||
tauri_config: &ConfigMetadata,
|
||||
pbxproj: &mut pbxproj::Pbxproj,
|
||||
export_options_plist: &mut plist::Dictionary,
|
||||
project_config: &ProjectConfig,
|
||||
debug: bool,
|
||||
) -> Result<()> {
|
||||
let identifier = tauri_config
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.identifier
|
||||
.clone();
|
||||
let product_name = tauri_config
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.product_name
|
||||
.clone();
|
||||
let identifier = tauri_config.identifier.clone();
|
||||
let product_name = tauri_config.product_name.clone();
|
||||
|
||||
let manual_signing = project_config.code_sign_identity.is_some()
|
||||
|| project_config.provisioning_profile_uuid.is_some();
|
||||
|
||||
@ -10,6 +10,7 @@ use clap::{ArgAction, Parser};
|
||||
use super::{device_prompt, env};
|
||||
use crate::{
|
||||
error::Context,
|
||||
helpers::config::{get_config as get_tauri_config, ConfigMetadata},
|
||||
interface::{DevProcess, Interface, WatcherOptions},
|
||||
mobile::{DevChild, TargetDevice},
|
||||
ConfigValue, Result,
|
||||
@ -26,7 +27,7 @@ pub struct Options {
|
||||
pub release: bool,
|
||||
/// List of cargo features to activate
|
||||
#[clap(short, long, action = ArgAction::Append, num_args(0..))]
|
||||
pub features: Option<Vec<String>>,
|
||||
pub features: Vec<String>,
|
||||
/// JSON strings or paths to JSON, JSON5 or TOML files to merge with the default configuration file
|
||||
///
|
||||
/// Configurations are merged in the order they are provided, which means a particular value overwrites previous values when a config key-value pair conflicts.
|
||||
@ -73,11 +74,13 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> {
|
||||
}
|
||||
};
|
||||
|
||||
let dirs = crate::helpers::app_paths::resolve_dirs();
|
||||
|
||||
let mut built_application = super::build::command(
|
||||
super::build::Options {
|
||||
debug: !options.release,
|
||||
targets: Some(vec![]), /* skips IPA build since there's no target */
|
||||
features: None,
|
||||
features: Vec::new(),
|
||||
config: options.config.clone(),
|
||||
build_number: None,
|
||||
open: options.open,
|
||||
@ -91,12 +94,19 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> {
|
||||
}),
|
||||
},
|
||||
noise_level,
|
||||
&dirs,
|
||||
)?;
|
||||
|
||||
let mut tauri_config = get_tauri_config(
|
||||
tauri_utils::platform::Target::Ios,
|
||||
&options.config.iter().map(|c| &c.0).collect::<Vec<_>>(),
|
||||
dirs.tauri,
|
||||
)?;
|
||||
|
||||
// options.open is handled by the build command
|
||||
// so all we need to do here is run the app on the selected device
|
||||
if let Some(device) = device {
|
||||
let runner = move || {
|
||||
let runner = move |_tauri_config: &ConfigMetadata| {
|
||||
device
|
||||
.run(
|
||||
&built_application.config,
|
||||
@ -114,14 +124,16 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> {
|
||||
};
|
||||
|
||||
if options.no_watch {
|
||||
runner()?;
|
||||
runner(&tauri_config)?;
|
||||
} else {
|
||||
built_application.interface.watch(
|
||||
&mut tauri_config,
|
||||
WatcherOptions {
|
||||
config: options.config,
|
||||
additional_watch_folders: options.additional_watch_folders,
|
||||
},
|
||||
runner,
|
||||
&dirs,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
use super::{ensure_init, env, get_app, get_config, read_options, MobileTarget};
|
||||
use crate::{
|
||||
error::{Context, ErrorExt},
|
||||
helpers::config::{get as get_tauri_config, reload as reload_tauri_config},
|
||||
helpers::config::{get_config as get_tauri_config, reload_config as reload_tauri_config},
|
||||
interface::{AppInterface, Interface, Options as InterfaceOptions},
|
||||
mobile::ios::LIB_OUTPUT_FILE_NAME,
|
||||
Error, Result,
|
||||
@ -89,47 +89,43 @@ pub fn command(options: Options) -> Result<()> {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
crate::helpers::app_paths::resolve();
|
||||
let dirs = crate::helpers::app_paths::resolve_dirs();
|
||||
|
||||
let profile = profile_from_configuration(&options.configuration);
|
||||
let macos = macos_from_platform(&options.platform);
|
||||
|
||||
let (tauri_config, cli_options) = {
|
||||
let tauri_config = get_tauri_config(tauri_utils::platform::Target::Ios, &[])?;
|
||||
let cli_options = {
|
||||
let tauri_config_guard = tauri_config.lock().unwrap();
|
||||
let tauri_config_ = tauri_config_guard.as_ref().unwrap();
|
||||
read_options(tauri_config_)
|
||||
};
|
||||
let tauri_config = if cli_options.config.is_empty() {
|
||||
tauri_config
|
||||
} else {
|
||||
let mut tauri_config = get_tauri_config(tauri_utils::platform::Target::Ios, &[], dirs.tauri)?;
|
||||
let cli_options = {
|
||||
let cli_options = { read_options(&tauri_config) };
|
||||
if !cli_options.config.is_empty() {
|
||||
// reload config with merges from the ios dev|build script
|
||||
reload_tauri_config(
|
||||
&mut tauri_config,
|
||||
&cli_options
|
||||
.config
|
||||
.iter()
|
||||
.map(|conf| &conf.0)
|
||||
.collect::<Vec<_>>(),
|
||||
dirs.tauri,
|
||||
)?
|
||||
};
|
||||
|
||||
(tauri_config, cli_options)
|
||||
cli_options
|
||||
};
|
||||
|
||||
let (config, metadata) = {
|
||||
let tauri_config_guard = tauri_config.lock().unwrap();
|
||||
let tauri_config_ = tauri_config_guard.as_ref().unwrap();
|
||||
let cli_options = read_options(tauri_config_);
|
||||
let cli_options = read_options(&tauri_config);
|
||||
let (config, metadata) = get_config(
|
||||
&get_app(
|
||||
MobileTarget::Ios,
|
||||
tauri_config_,
|
||||
&AppInterface::new(tauri_config_, None)?,
|
||||
&tauri_config,
|
||||
&AppInterface::new(&tauri_config, None, dirs.tauri)?,
|
||||
dirs.tauri,
|
||||
),
|
||||
tauri_config_,
|
||||
None,
|
||||
&tauri_config,
|
||||
&[],
|
||||
&cli_options,
|
||||
dirs.tauri,
|
||||
)?;
|
||||
(config, metadata)
|
||||
};
|
||||
@ -142,7 +138,8 @@ pub fn command(options: Options) -> Result<()> {
|
||||
)?;
|
||||
|
||||
if !cli_options.config.is_empty() {
|
||||
crate::helpers::config::merge_with(
|
||||
crate::helpers::config::merge_config_with(
|
||||
&mut tauri_config,
|
||||
&cli_options
|
||||
.config
|
||||
.iter()
|
||||
@ -236,10 +233,7 @@ pub fn command(options: Options) -> Result<()> {
|
||||
}
|
||||
};
|
||||
|
||||
let interface = AppInterface::new(
|
||||
tauri_config.lock().unwrap().as_ref().unwrap(),
|
||||
Some(rust_triple.into()),
|
||||
)?;
|
||||
let interface = AppInterface::new(&tauri_config, Some(rust_triple.into()), dirs.tauri)?;
|
||||
|
||||
let cflags = format!("CFLAGS_{env_triple}");
|
||||
let cxxflags = format!("CFLAGS_{env_triple}");
|
||||
@ -280,11 +274,14 @@ pub fn command(options: Options) -> Result<()> {
|
||||
)
|
||||
.context("failed to compile iOS app")?;
|
||||
|
||||
let out_dir = interface.app_settings().out_dir(&InterfaceOptions {
|
||||
debug: matches!(profile, Profile::Debug),
|
||||
target: Some(rust_triple.into()),
|
||||
..Default::default()
|
||||
})?;
|
||||
let out_dir = interface.app_settings().out_dir(
|
||||
&InterfaceOptions {
|
||||
debug: matches!(profile, Profile::Debug),
|
||||
target: Some(rust_triple.into()),
|
||||
..Default::default()
|
||||
},
|
||||
dirs.tauri,
|
||||
)?;
|
||||
|
||||
let lib_path = out_dir.join(format!("lib{}.a", config.app().lib_name()));
|
||||
if !lib_path.exists() {
|
||||
|
||||
@ -4,10 +4,7 @@
|
||||
|
||||
use crate::{
|
||||
error::{Context, ErrorExt},
|
||||
helpers::{
|
||||
app_paths::tauri_dir,
|
||||
config::{reload as reload_config, Config as TauriConfig, ConfigHandle, ConfigMetadata},
|
||||
},
|
||||
helpers::config::{reload_config, Config as TauriConfig, ConfigMetadata},
|
||||
interface::{AppInterface, AppSettings, DevProcess, Interface, Options as InterfaceOptions},
|
||||
ConfigValue, Error, Result,
|
||||
};
|
||||
@ -31,7 +28,7 @@ use std::{
|
||||
fmt::{Display, Write},
|
||||
fs::{read_to_string, write},
|
||||
net::{AddrParseError, IpAddr, Ipv4Addr, SocketAddr},
|
||||
path::PathBuf,
|
||||
path::{Path, PathBuf},
|
||||
process::{exit, ExitStatus},
|
||||
str::FromStr,
|
||||
sync::{
|
||||
@ -181,7 +178,7 @@ impl Default for DevHost {
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct CliOptions {
|
||||
pub dev: bool,
|
||||
pub features: Option<Vec<String>>,
|
||||
pub features: Vec<String>,
|
||||
pub args: Vec<String>,
|
||||
pub noise_level: NoiseLevel,
|
||||
pub vars: HashMap<String, OsString>,
|
||||
@ -193,7 +190,7 @@ impl Default for CliOptions {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
dev: false,
|
||||
features: None,
|
||||
features: Vec::new(),
|
||||
args: vec!["--lib".into()],
|
||||
noise_level: Default::default(),
|
||||
vars: Default::default(),
|
||||
@ -217,12 +214,9 @@ fn local_ip_address(force: bool) -> &'static IpAddr {
|
||||
|
||||
})
|
||||
.collect();
|
||||
match addresses.len() {
|
||||
0 => panic!("No external IP detected."),
|
||||
1 => {
|
||||
let ipaddr = addresses.first().unwrap();
|
||||
*ipaddr
|
||||
}
|
||||
match addresses.as_slice() {
|
||||
[] => panic!("No external IP detected."),
|
||||
[ipaddr] => *ipaddr,
|
||||
_ => {
|
||||
let selected = dialoguer::Select::with_theme(&dialoguer::theme::ColorfulTheme::default())
|
||||
.with_prompt(
|
||||
@ -252,18 +246,12 @@ struct DevUrlConfig {
|
||||
}
|
||||
|
||||
fn use_network_address_for_dev_url(
|
||||
config: &ConfigHandle,
|
||||
config: &mut ConfigMetadata,
|
||||
dev_options: &mut crate::dev::Options,
|
||||
force_ip_prompt: bool,
|
||||
tauri_dir: &Path,
|
||||
) -> crate::Result<DevUrlConfig> {
|
||||
let mut dev_url = config
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.build
|
||||
.dev_url
|
||||
.clone();
|
||||
let mut dev_url = config.build.dev_url.clone();
|
||||
|
||||
let ip = if let Some(url) = &mut dev_url {
|
||||
let localhost = match url.host() {
|
||||
@ -299,11 +287,13 @@ fn use_network_address_for_dev_url(
|
||||
})));
|
||||
|
||||
reload_config(
|
||||
config,
|
||||
&dev_options
|
||||
.config
|
||||
.iter()
|
||||
.map(|conf| &conf.0)
|
||||
.collect::<Vec<_>>(),
|
||||
tauri_dir,
|
||||
)?;
|
||||
|
||||
Some(ip)
|
||||
@ -441,7 +431,12 @@ fn read_options(config: &ConfigMetadata) -> CliOptions {
|
||||
options
|
||||
}
|
||||
|
||||
pub fn get_app(target: Target, config: &TauriConfig, interface: &AppInterface) -> App {
|
||||
pub fn get_app(
|
||||
target: Target,
|
||||
config: &TauriConfig,
|
||||
interface: &AppInterface,
|
||||
tauri_dir: &Path,
|
||||
) -> App {
|
||||
let identifier = match target {
|
||||
Target::Android => config.identifier.replace('-', "_"),
|
||||
#[cfg(target_os = "macos")]
|
||||
@ -478,22 +473,26 @@ pub fn get_app(target: Target, config: &TauriConfig, interface: &AppInterface) -
|
||||
};
|
||||
|
||||
let app_settings = interface.app_settings();
|
||||
App::from_raw(tauri_dir().to_path_buf(), raw)
|
||||
let tauri_dir = tauri_dir.to_path_buf();
|
||||
App::from_raw(tauri_dir.to_path_buf(), raw)
|
||||
.unwrap()
|
||||
.with_target_dir_resolver(move |target, profile| {
|
||||
app_settings
|
||||
.out_dir(&InterfaceOptions {
|
||||
debug: matches!(profile, Profile::Debug),
|
||||
target: Some(target.into()),
|
||||
..Default::default()
|
||||
})
|
||||
.out_dir(
|
||||
&InterfaceOptions {
|
||||
debug: matches!(profile, Profile::Debug),
|
||||
target: Some(target.into()),
|
||||
..Default::default()
|
||||
},
|
||||
&tauri_dir,
|
||||
)
|
||||
.expect("failed to resolve target directory")
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn ensure_init(
|
||||
tauri_config: &ConfigHandle,
|
||||
tauri_config: &ConfigMetadata,
|
||||
app: &App,
|
||||
project_dir: PathBuf,
|
||||
target: Target,
|
||||
@ -508,16 +507,13 @@ fn ensure_init(
|
||||
)
|
||||
}
|
||||
|
||||
let tauri_config_guard = tauri_config.lock().unwrap();
|
||||
let tauri_config_ = tauri_config_guard.as_ref().unwrap();
|
||||
|
||||
let mut project_outdated_reasons = Vec::new();
|
||||
|
||||
match target {
|
||||
Target::Android => {
|
||||
let java_folder = project_dir
|
||||
.join("app/src/main/java")
|
||||
.join(tauri_config_.identifier.replace('.', "/").replace('-', "_"));
|
||||
.join(tauri_config.identifier.replace('.', "/").replace('-', "_"));
|
||||
if java_folder.exists() {
|
||||
#[cfg(unix)]
|
||||
ensure_gradlew(&project_dir)?;
|
||||
|
||||
@ -6,11 +6,7 @@ use clap::Parser;
|
||||
|
||||
use crate::{
|
||||
acl,
|
||||
helpers::{
|
||||
app_paths::{resolve_frontend_dir, tauri_dir},
|
||||
cargo,
|
||||
npm::PackageManager,
|
||||
},
|
||||
helpers::{app_paths::resolve_frontend_dir, cargo, npm::PackageManager},
|
||||
Result,
|
||||
};
|
||||
|
||||
@ -22,11 +18,7 @@ pub struct Options {
|
||||
}
|
||||
|
||||
pub fn command(options: Options) -> Result<()> {
|
||||
crate::helpers::app_paths::resolve();
|
||||
run(options)
|
||||
}
|
||||
|
||||
pub fn run(options: Options) -> Result<()> {
|
||||
let dirs = crate::helpers::app_paths::resolve_dirs();
|
||||
let plugin = options.plugin;
|
||||
|
||||
let crate_name = format!("tauri-plugin-{plugin}");
|
||||
@ -35,7 +27,6 @@ pub fn run(options: Options) -> Result<()> {
|
||||
let metadata = plugins.remove(plugin.as_str()).unwrap_or_default();
|
||||
|
||||
let frontend_dir = resolve_frontend_dir();
|
||||
let tauri_dir = tauri_dir();
|
||||
|
||||
let target_str = metadata
|
||||
.desktop_only
|
||||
@ -48,14 +39,14 @@ pub fn run(options: Options) -> Result<()> {
|
||||
|
||||
cargo::uninstall_one(cargo::CargoUninstallOptions {
|
||||
name: &crate_name,
|
||||
cwd: Some(tauri_dir),
|
||||
cwd: Some(dirs.tauri),
|
||||
target: target_str,
|
||||
})?;
|
||||
|
||||
if !metadata.rust_only {
|
||||
if let Some(manager) = frontend_dir.map(PackageManager::from_project) {
|
||||
let npm_name = format!("@tauri-apps/plugin-{plugin}");
|
||||
manager.remove(&[npm_name], tauri_dir)?;
|
||||
manager.remove(&[npm_name], dirs.tauri)?;
|
||||
}
|
||||
|
||||
acl::permission::rm::command(acl::permission::rm::Options {
|
||||
|
||||
@ -39,26 +39,29 @@ pub fn command(mut options: Options) -> Result<()> {
|
||||
save_keypair(options.force, output_path, &keypair.sk, &keypair.pk)
|
||||
.expect("Unable to write keypair");
|
||||
|
||||
println!(
|
||||
"\nYour keypair was generated successfully\nPrivate: {} (Keep it secret!)\nPublic: {}\n---------------------------",
|
||||
display_path(secret_path),
|
||||
display_path(public_path)
|
||||
)
|
||||
println!();
|
||||
println!("Your keypair was generated successfully:");
|
||||
println!("Private: {} (Keep it secret!)", display_path(secret_path));
|
||||
println!("Public: {}", display_path(public_path));
|
||||
println!("---------------------------")
|
||||
} else {
|
||||
println!(
|
||||
"\nYour secret key was generated successfully - Keep it secret!\n{}\n\n",
|
||||
keypair.sk
|
||||
);
|
||||
println!(
|
||||
"Your public key was generated successfully:\n{}\n\nAdd the public key in your tauri.conf.json\n---------------------------\n",
|
||||
keypair.pk
|
||||
);
|
||||
println!();
|
||||
println!("Your keys were generated successfully!",);
|
||||
println!();
|
||||
println!("Private: (Keep it secret!)");
|
||||
println!("{}", keypair.sk);
|
||||
println!();
|
||||
println!("Public:");
|
||||
println!("{}", keypair.pk);
|
||||
}
|
||||
|
||||
println!("\nEnvironment variables used to sign:");
|
||||
println!("`TAURI_SIGNING_PRIVATE_KEY` Path or String of your private key");
|
||||
println!("`TAURI_SIGNING_PRIVATE_KEY_PASSWORD` Your private key password (optional)");
|
||||
println!("\nATTENTION: If you lose your private key OR password, you'll not be able to sign your update package and updates will not work.\n---------------------------\n");
|
||||
println!();
|
||||
println!("Environment variables used to sign:");
|
||||
println!("- `TAURI_SIGNING_PRIVATE_KEY`: String of your private key");
|
||||
println!("- `TAURI_SIGNING_PRIVATE_KEY_PATH`: Path to your private key file");
|
||||
println!("- `TAURI_SIGNING_PRIVATE_KEY_PASSWORD`: Your private key password (optional if key has no password)");
|
||||
println!();
|
||||
println!("ATTENTION: If you lose your private key OR password, you'll not be able to sign your update package and updates will not work");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@ pub struct Options {
|
||||
short = 'k',
|
||||
long,
|
||||
conflicts_with("private_key_path"),
|
||||
env = "TAURI_PRIVATE_KEY"
|
||||
env = "TAURI_SIGNING_PRIVATE_KEY"
|
||||
)]
|
||||
private_key: Option<String>,
|
||||
/// Load the private key from a file
|
||||
@ -29,17 +29,50 @@ pub struct Options {
|
||||
short = 'f',
|
||||
long,
|
||||
conflicts_with("private_key"),
|
||||
env = "TAURI_PRIVATE_KEY_PATH"
|
||||
env = "TAURI_SIGNING_PRIVATE_KEY_PATH"
|
||||
)]
|
||||
private_key_path: Option<PathBuf>,
|
||||
/// Set private key password when signing
|
||||
#[clap(short, long, env = "TAURI_PRIVATE_KEY_PASSWORD")]
|
||||
#[clap(short, long, env = "TAURI_SIGNING_PRIVATE_KEY_PASSWORD")]
|
||||
password: Option<String>,
|
||||
/// Sign the specified file
|
||||
file: PathBuf,
|
||||
}
|
||||
|
||||
// Backwards compatibility with old env vars
|
||||
// TODO: remove in v3.0
|
||||
fn backward_env_vars(mut options: Options) -> Options {
|
||||
let get_env = |old, new| {
|
||||
if let Ok(old_value) = std::env::var(old) {
|
||||
println!(
|
||||
"\x1b[33mWarning: The environment variable '{old}' is deprecated. Please use '{new}' instead.\x1b[0m",
|
||||
);
|
||||
Some(old_value)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
options.private_key = options
|
||||
.private_key
|
||||
.or_else(|| get_env("TAURI_PRIVATE_KEY", "TAURI_SIGNING_PRIVATE_KEY"));
|
||||
|
||||
options.private_key_path = options.private_key_path.or_else(|| {
|
||||
get_env("TAURI_PRIVATE_KEY_PATH", "TAURI_SIGNING_PRIVATE_KEY_PATH").map(PathBuf::from)
|
||||
});
|
||||
|
||||
options.password = options.password.or_else(|| {
|
||||
get_env(
|
||||
"TAURI_PRIVATE_KEY_PASSWORD",
|
||||
"TAURI_SIGNING_PRIVATE_KEY_PASSWORD",
|
||||
)
|
||||
});
|
||||
options
|
||||
}
|
||||
|
||||
pub fn command(mut options: Options) -> Result<()> {
|
||||
options = backward_env_vars(options);
|
||||
|
||||
options.private_key = if let Some(private_key) = options.private_key_path {
|
||||
Some(std::fs::read_to_string(Path::new(&private_key)).expect("Unable to extract private key"))
|
||||
} else {
|
||||
|
||||
@ -31,8 +31,8 @@ tokio = { version = "1", features = ["macros"] }
|
||||
which = "8"
|
||||
|
||||
[target."cfg(unix)".dependencies]
|
||||
signal-hook = "0.3"
|
||||
signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] }
|
||||
signal-hook = "0.4"
|
||||
signal-hook-tokio = { version = "0.4", features = ["futures-v0_3"] }
|
||||
|
||||
[target."cfg(windows)".dependencies]
|
||||
win32job = "2"
|
||||
|
||||
@ -15,7 +15,8 @@ serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
tempfile = "3"
|
||||
x509-certificate = "0.23"
|
||||
once-cell-regex = "0.2"
|
||||
once_cell = "1"
|
||||
regex = "1"
|
||||
os_pipe = "1"
|
||||
plist = "1"
|
||||
rand = "0.9"
|
||||
|
||||
@ -2,7 +2,8 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use once_cell_regex::regex;
|
||||
use once_cell::sync::OnceCell;
|
||||
use regex::Regex;
|
||||
use std::{collections::BTreeSet, path::Path, process::Command};
|
||||
use x509_certificate::certificate::X509Certificate;
|
||||
|
||||
@ -49,9 +50,10 @@ impl Team {
|
||||
organization
|
||||
} else {
|
||||
println!(
|
||||
"found cert {common_name:?} but failed to get organization; falling back to displaying common name"
|
||||
);
|
||||
regex!(r"Apple Develop\w+: (.*) \(.+\)")
|
||||
"found cert {common_name:?} but failed to get organization; falling back to displaying common name"
|
||||
);
|
||||
static APPLE_DEV: OnceCell<Regex> = OnceCell::new();
|
||||
APPLE_DEV.get_or_init(|| Regex::new(r"Apple Develop\w+: (.*) \(.+\)").unwrap())
|
||||
.captures(&common_name)
|
||||
.map(|caps| caps[1].to_owned())
|
||||
.unwrap_or_else(|| {
|
||||
|
||||
@ -13,7 +13,7 @@ edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
wry = { version = "0.53.4", default-features = false, features = [
|
||||
wry = { version = "0.54.0", default-features = false, features = [
|
||||
"drag-drop",
|
||||
"protocol",
|
||||
"os-webview",
|
||||
|
||||
@ -37,7 +37,13 @@ use tauri_runtime::{
|
||||
use objc2::rc::Retained;
|
||||
#[cfg(target_os = "macos")]
|
||||
use tao::platform::macos::{EventLoopWindowTargetExtMacOS, WindowBuilderExtMacOS};
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
use tao::platform::unix::{WindowBuilderExtUnix, WindowExtUnix};
|
||||
#[cfg(windows)]
|
||||
use tao::platform::windows::{WindowBuilderExtWindows, WindowExtWindows};
|
||||
@ -862,7 +868,13 @@ impl WindowBuilder for WindowBuilderWrapper {
|
||||
");
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
{
|
||||
// Mouse event is disabled on Linux since sudden event bursts could block event loop.
|
||||
window.inner = window.inner.with_cursor_moved_event(false);
|
||||
@ -1194,7 +1206,14 @@ impl WindowBuilder for WindowBuilderWrapper {
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(any(windows, target_os = "linux"))]
|
||||
#[cfg(any(
|
||||
windows,
|
||||
target_os = "linux",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
fn skip_taskbar(mut self, skip: bool) -> Self {
|
||||
self.inner = self.inner.with_skip_taskbar(skip);
|
||||
self
|
||||
@ -3417,7 +3436,14 @@ fn handle_user_message<T: UserEvent>(
|
||||
}
|
||||
#[allow(unused_variables)]
|
||||
WindowMessage::SetSkipTaskbar(skip) => {
|
||||
#[cfg(any(windows, target_os = "linux"))]
|
||||
#[cfg(any(
|
||||
windows,
|
||||
target_os = "linux",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
let _ = window.set_skip_taskbar(skip);
|
||||
}
|
||||
WindowMessage::SetCursorGrab(grab) => {
|
||||
|
||||
@ -39,7 +39,7 @@ pub trait WindowExt {
|
||||
/// - **Android / iOS**: Unsupported.
|
||||
fn center(&self) {}
|
||||
|
||||
/// Clears the window surface. i.e make it it transparent.
|
||||
/// Clears the window surface. i.e make it transparent.
|
||||
#[cfg(windows)]
|
||||
fn draw_surface(
|
||||
&self,
|
||||
|
||||
@ -399,8 +399,25 @@ pub trait Runtime<T: UserEvent>: Debug + Sized + 'static {
|
||||
fn new(args: RuntimeInitArgs) -> Result<Self>;
|
||||
|
||||
/// Creates a new webview runtime on any thread.
|
||||
#[cfg(any(windows, target_os = "linux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(windows, target_os = "linux"))))]
|
||||
#[cfg(any(
|
||||
windows,
|
||||
target_os = "linux",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
#[cfg_attr(
|
||||
docsrs,
|
||||
doc(cfg(any(
|
||||
windows,
|
||||
target_os = "linux",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
)))
|
||||
)]
|
||||
fn new_any_thread(args: RuntimeInitArgs) -> Result<Self>;
|
||||
|
||||
/// Creates an `EventLoopProxy` that can be used to dispatch user events to the main event loop.
|
||||
|
||||
@ -363,7 +363,7 @@ pub struct WebviewAttributes {
|
||||
/// see https://docs.rs/objc2-web-kit/latest/objc2_web_kit/struct.WKWebView.html#method.allowsLinkPreview
|
||||
pub allow_link_preview: bool,
|
||||
pub scroll_bar_style: ScrollBarStyle,
|
||||
/// Allows overriding the the keyboard accessory view on iOS.
|
||||
/// Allows overriding the keyboard accessory view on iOS.
|
||||
/// Returning `None` effectively removes the view.
|
||||
///
|
||||
/// The closure parameter is the webview instance.
|
||||
|
||||
@ -165,7 +165,7 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"windows": {
|
||||
"description": "The app windows configuration.\n\n ## Example:\n\n To create a window at app startup\n\n ```json\n {\n \"app\": {\n \"windows\": [\n { \"width\": 800, \"height\": 600 }\n ]\n }\n }\n ```\n\n If not specified, the window's label (its identifier) defaults to \"main\",\n you can use this label to get the window through\n `app.get_webview_window` in Rust or `WebviewWindow.getByLabel` in JavaScript\n\n When working with multiple windows, each window will need an unique label\n\n ```json\n {\n \"app\": {\n \"windows\": [\n { \"label\": \"main\", \"width\": 800, \"height\": 600 },\n { \"label\": \"secondary\", \"width\": 800, \"height\": 600 }\n ]\n }\n }\n ```\n\n You can also set `create` to false and use this config through the Rust APIs\n\n ```json\n {\n \"app\": {\n \"windows\": [\n { \"create\": false, \"width\": 800, \"height\": 600 }\n ]\n }\n }\n ```\n\n and use it like this\n\n ```rust\n tauri::Builder::default()\n .setup(|app| {\n tauri::WebviewWindowBuilder::from_config(app.handle(), app.config().app.windows[0])?.build()?;\n Ok(())\n });\n ```",
|
||||
"description": "The app windows configuration.\n\n ## Example:\n\n To create a window at app startup\n\n ```json\n {\n \"app\": {\n \"windows\": [\n { \"width\": 800, \"height\": 600 }\n ]\n }\n }\n ```\n\n If not specified, the window's label (its identifier) defaults to \"main\",\n you can use this label to get the window through\n `app.get_webview_window` in Rust or `WebviewWindow.getByLabel` in JavaScript\n\n When working with multiple windows, each window will need an unique label\n\n ```json\n {\n \"app\": {\n \"windows\": [\n { \"label\": \"main\", \"width\": 800, \"height\": 600 },\n { \"label\": \"secondary\", \"width\": 800, \"height\": 600 }\n ]\n }\n }\n ```\n\n You can also set `create` to false and use this config through the Rust APIs\n\n ```json\n {\n \"app\": {\n \"windows\": [\n { \"create\": false, \"width\": 800, \"height\": 600 }\n ]\n }\n }\n ```\n\n and use it like this\n\n ```rust\n tauri::Builder::default()\n .setup(|app| {\n tauri::WebviewWindowBuilder::from_config(app.handle(), &app.config().app.windows[0])?.build()?;\n Ok(())\n });\n ```",
|
||||
"default": [],
|
||||
"type": "array",
|
||||
"items": {
|
||||
|
||||
@ -57,6 +57,7 @@ swift-rs = { version = "1", optional = true, features = ["build"] }
|
||||
[dev-dependencies]
|
||||
getrandom = { version = "0.3", features = ["std"] }
|
||||
serial_test = "3"
|
||||
tauri = { path = "../tauri" }
|
||||
|
||||
[features]
|
||||
build = [
|
||||
|
||||
@ -2742,7 +2742,7 @@ pub struct AppConfig {
|
||||
/// ```rust
|
||||
/// tauri::Builder::default()
|
||||
/// .setup(|app| {
|
||||
/// tauri::WebviewWindowBuilder::from_config(app.handle(), app.config().app.windows[0])?.build()?;
|
||||
/// tauri::WebviewWindowBuilder::from_config(app.handle(), &app.config().app.windows[0])?.build()?;
|
||||
/// Ok(())
|
||||
/// });
|
||||
/// ```
|
||||
|
||||
@ -344,23 +344,20 @@ fn resource_dir_from<P: AsRef<std::path::Path>>(
|
||||
// Variable holding the type of bundle the executable is stored in. This is modified by binary
|
||||
// patching during build
|
||||
#[used]
|
||||
#[no_mangle]
|
||||
#[cfg_attr(not(target_vendor = "apple"), link_section = ".taubndl")]
|
||||
#[cfg_attr(target_vendor = "apple", link_section = "__DATA,taubndl")]
|
||||
// Marked as `mut` because it could get optimized away without it,
|
||||
// see https://github.com/tauri-apps/tauri/pull/13812
|
||||
static mut __TAURI_BUNDLE_TYPE: &str = "UNK";
|
||||
static mut __TAURI_BUNDLE_TYPE: &str = "__TAURI_BUNDLE_TYPE_VAR_UNK";
|
||||
|
||||
/// Get the type of the bundle current binary is packaged in.
|
||||
/// If the bundle type is unknown, it returns [`Option::None`].
|
||||
pub fn bundle_type() -> Option<BundleType> {
|
||||
unsafe {
|
||||
match __TAURI_BUNDLE_TYPE {
|
||||
"DEB" => Some(BundleType::Deb),
|
||||
"RPM" => Some(BundleType::Rpm),
|
||||
"APP" => Some(BundleType::AppImage),
|
||||
"MSI" => Some(BundleType::Msi),
|
||||
"NSS" => Some(BundleType::Nsis),
|
||||
"__TAURI_BUNDLE_TYPE_VAR_DEB" => Some(BundleType::Deb),
|
||||
"__TAURI_BUNDLE_TYPE_VAR_RPM" => Some(BundleType::Rpm),
|
||||
"__TAURI_BUNDLE_TYPE_VAR_APP" => Some(BundleType::AppImage),
|
||||
"__TAURI_BUNDLE_TYPE_VAR_MSI" => Some(BundleType::Msi),
|
||||
"__TAURI_BUNDLE_TYPE_VAR_NSS" => Some(BundleType::Nsis),
|
||||
_ => {
|
||||
if cfg!(target_os = "macos") {
|
||||
Some(BundleType::App)
|
||||
|
||||
@ -97,7 +97,7 @@ tray-icon = { version = "0.21", default-features = false, features = [
|
||||
# linux
|
||||
[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))'.dependencies]
|
||||
gtk = { version = "0.18", features = ["v3_24"] }
|
||||
webkit2gtk = { version = "=2.0.1", features = ["v2_40"], optional = true }
|
||||
webkit2gtk = { version = "=2.0.2", features = ["v2_40"], optional = true }
|
||||
|
||||
# darwin
|
||||
[target.'cfg(target_vendor = "apple")'.dependencies]
|
||||
@ -141,11 +141,13 @@ windows = { version = "0.61", features = [
|
||||
# mobile
|
||||
[target.'cfg(any(target_os = "android", all(target_vendor = "apple", not(target_os = "macos"))))'.dependencies]
|
||||
bytes = { version = "1", features = ["serde"] }
|
||||
reqwest = { version = "0.12", default-features = false, features = [
|
||||
reqwest = { version = "0.13", default-features = false, features = [
|
||||
"json",
|
||||
"stream",
|
||||
|
||||
] }
|
||||
rustls = { version = "0.23", default-features = false, features = [
|
||||
"ring",
|
||||
], optional = true }
|
||||
|
||||
# android
|
||||
[target.'cfg(target_os = "android")'.dependencies]
|
||||
@ -198,10 +200,9 @@ linux-libxdo = ["tray-icon/libxdo", "muda/libxdo"]
|
||||
isolation = ["tauri-utils/isolation", "tauri-macros/isolation", "uuid"]
|
||||
custom-protocol = ["tauri-macros/custom-protocol"]
|
||||
# TODO: Remove these flags in v3 and/or enable them by default behind a mobile flag https://github.com/tauri-apps/tauri/issues/12384
|
||||
# For now those feature flags keep enabling reqwest features in case some users depend on that by accident.
|
||||
native-tls = ["reqwest/native-tls"]
|
||||
native-tls-vendored = ["reqwest/native-tls-vendored"]
|
||||
rustls-tls = ["reqwest/rustls-tls"]
|
||||
rustls-tls = ["reqwest/rustls-no-provider", "dep:rustls"]
|
||||
devtools = ["tauri-runtime/devtools", "tauri-runtime-wry?/devtools"]
|
||||
process-relaunch-dangerous-allow-symlink-macos = [
|
||||
"tauri-utils/process-relaunch-dangerous-allow-symlink-macos",
|
||||
|
||||
@ -129,14 +129,7 @@ fn replace_csp_nonce(
|
||||
) {
|
||||
let mut nonces = Vec::new();
|
||||
*asset = replace_with_callback(asset, token, || {
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
let mut raw = [0u8; 8];
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
let mut raw = [0u8; 4];
|
||||
#[cfg(target_pointer_width = "16")]
|
||||
let mut raw = [0u8; 2];
|
||||
getrandom::fill(&mut raw).expect("failed to get random bytes");
|
||||
let nonce = usize::from_ne_bytes(raw);
|
||||
let nonce = getrandom::u64().expect("failed to get random bytes");
|
||||
nonces.push(nonce);
|
||||
nonce.to_string()
|
||||
});
|
||||
|
||||
@ -48,9 +48,29 @@ fn get_response(
|
||||
return resp.status(403).body(Vec::new().into()).map_err(Into::into);
|
||||
}
|
||||
|
||||
let (mut file, len, mime_type, read_bytes) = crate::async_runtime::safe_block_on(async move {
|
||||
let mut file = File::open(&path).await?;
|
||||
// Separate block for easier error handling
|
||||
let mut file = match crate::async_runtime::safe_block_on(File::open(path.clone())) {
|
||||
Ok(file) => file,
|
||||
Err(e) => {
|
||||
#[cfg(target_os = "android")]
|
||||
{
|
||||
if path.starts_with("/storage/emulated/0/Android/data/") {
|
||||
log::error!("Failed to open Android external storage file '{}': {}. This may be due to missing storage permissions.", path, e);
|
||||
}
|
||||
}
|
||||
return if e.kind() == std::io::ErrorKind::NotFound {
|
||||
log::error!("File does not exist at path: {}", path);
|
||||
return resp.status(404).body(Vec::new().into()).map_err(Into::into);
|
||||
} else if e.kind() == std::io::ErrorKind::PermissionDenied {
|
||||
log::error!("Missing OS permission to access path \"{}\": {}", path, e);
|
||||
return resp.status(403).body(Vec::new().into()).map_err(Into::into);
|
||||
} else {
|
||||
Err(e.into())
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
let (mut file, len, mime_type, read_bytes) = crate::async_runtime::safe_block_on(async move {
|
||||
// get file length
|
||||
let len = {
|
||||
let old_pos = file.stream_position().await?;
|
||||
|
||||
@ -114,6 +114,11 @@ fn get_response<R: Runtime>(
|
||||
decoded_path.trim_start_matches('/')
|
||||
);
|
||||
|
||||
#[cfg(feature = "rustls-tls")]
|
||||
if rustls::crypto::CryptoProvider::get_default().is_none() {
|
||||
let _ = rustls::crypto::ring::default_provider().install_default();
|
||||
}
|
||||
|
||||
let mut client = reqwest::ClientBuilder::new();
|
||||
|
||||
if url.starts_with("https://") {
|
||||
@ -126,10 +131,9 @@ fn get_response<R: Runtime>(
|
||||
))]
|
||||
{
|
||||
log::info!("adding dev server root certificate");
|
||||
client = client.add_root_certificate(
|
||||
reqwest::Certificate::from_pem(cert_pem.as_bytes())
|
||||
.expect("failed to parse TAURI_DEV_ROOT_CERTIFICATE"),
|
||||
);
|
||||
let certificate = reqwest::Certificate::from_pem(cert_pem.as_bytes())
|
||||
.expect("failed to parse TAURI_DEV_ROOT_CERTIFICATE");
|
||||
client = client.tls_certs_merge([certificate]);
|
||||
}
|
||||
|
||||
#[cfg(not(any(
|
||||
|
||||
@ -1146,7 +1146,14 @@ impl<T: UserEvent> Runtime<T> for MockRuntime {
|
||||
Ok(Self::init())
|
||||
}
|
||||
|
||||
#[cfg(any(windows, target_os = "linux"))]
|
||||
#[cfg(any(
|
||||
windows,
|
||||
target_os = "linux",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
fn new_any_thread(_args: RuntimeInitArgs) -> Result<Self> {
|
||||
Ok(Self::init())
|
||||
}
|
||||
|
||||
@ -1202,7 +1202,7 @@ fn main() {
|
||||
self
|
||||
}
|
||||
|
||||
/// Allows overriding the the keyboard accessory view on iOS.
|
||||
/// Allows overriding the keyboard accessory view on iOS.
|
||||
/// Returning `None` effectively removes the view.
|
||||
///
|
||||
/// The closure parameter is the webview instance.
|
||||
@ -2312,4 +2312,25 @@ mod tests {
|
||||
crate::test_utils::assert_send::<super::Webview>();
|
||||
crate::test_utils::assert_sync::<super::Webview>();
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[test]
|
||||
fn test_webview_window_has_set_simple_fullscreen_method() {
|
||||
use crate::test::{mock_builder, mock_context, noop_assets};
|
||||
|
||||
// Create a mock app with proper context
|
||||
let app = mock_builder().build(mock_context(noop_assets())).unwrap();
|
||||
|
||||
// Get or create a webview window
|
||||
let webview_window =
|
||||
crate::WebviewWindowBuilder::new(&app, "test", crate::WebviewUrl::default())
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
// This should compile if set_simple_fullscreen exists
|
||||
let result = webview_window.set_simple_fullscreen(true);
|
||||
|
||||
// We expect this to work without panicking
|
||||
assert!(result.is_ok(), "set_simple_fullscreen should succeed");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1230,7 +1230,7 @@ impl<R: Runtime, M: Manager<R>> WebviewWindowBuilder<'_, R, M> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Allows overriding the the keyboard accessory view on iOS.
|
||||
/// Allows overriding the keyboard accessory view on iOS.
|
||||
/// Returning `None` effectively removes the view.
|
||||
///
|
||||
/// The closure parameter is the webview instance.
|
||||
@ -2057,6 +2057,20 @@ impl<R: Runtime> WebviewWindow<R> {
|
||||
self.window.set_fullscreen(fullscreen)
|
||||
}
|
||||
|
||||
/// Toggles a fullscreen mode that doesn't require a new macOS space.
|
||||
/// Returns a boolean indicating whether the transition was successful (this won't work if the window was already in the native fullscreen).
|
||||
///
|
||||
/// This is how fullscreen used to work on macOS in versions before Lion.
|
||||
/// And allows the user to have a fullscreen window without using another space or taking control over the entire monitor.
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **macOS:** Uses native simple fullscreen mode.
|
||||
/// - **Other platforms:** Falls back to [`Self::set_fullscreen`].
|
||||
pub fn set_simple_fullscreen(&self, enable: bool) -> crate::Result<()> {
|
||||
self.window.set_simple_fullscreen(enable)
|
||||
}
|
||||
|
||||
/// Bring the window to front and focus.
|
||||
pub fn set_focus(&self) -> crate::Result<()> {
|
||||
self.window.set_focus()
|
||||
|
||||
@ -1968,25 +1968,27 @@ tauri::Builder::default()
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Toggles a fullscreen mode that doesn’t require a new macOS space. Returns a boolean indicating whether the transition was successful (this won’t work if the window was already in the native fullscreen).
|
||||
/// Toggles a fullscreen mode that doesn't require a new macOS space.
|
||||
/// Returns a boolean indicating whether the transition was successful (this won't work if the window was already in the native fullscreen).
|
||||
///
|
||||
/// This is how fullscreen used to work on macOS in versions before Lion. And allows the user to have a fullscreen window without using another space or taking control over the entire monitor.
|
||||
#[cfg(target_os = "macos")]
|
||||
/// This is how fullscreen used to work on macOS in versions before Lion.
|
||||
/// And allows the user to have a fullscreen window without using another space or taking control over the entire monitor.
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **macOS:** Uses native simple fullscreen mode.
|
||||
/// - **Other platforms:** Falls back to [`Self::set_fullscreen`].
|
||||
pub fn set_simple_fullscreen(&self, enable: bool) -> crate::Result<()> {
|
||||
self
|
||||
.window
|
||||
.dispatcher
|
||||
.set_simple_fullscreen(enable)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
/// On macOS, Toggles a fullscreen mode that doesn’t require a new macOS space. Returns a boolean indicating whether the transition was successful (this won’t work if the window was already in the native fullscreen).
|
||||
/// This is how fullscreen used to work on macOS in versions before Lion. And allows the user to have a fullscreen window without using another space or taking control over the entire monitor.
|
||||
///
|
||||
/// On other platforms, this is the same as [`Window#method.set_fullscreen`].
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
pub fn set_simple_fullscreen(&self, fullscreen: bool) -> crate::Result<()> {
|
||||
self.set_fullscreen(fullscreen)
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
self
|
||||
.window
|
||||
.dispatcher
|
||||
.set_simple_fullscreen(enable)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
self.set_fullscreen(enable)
|
||||
}
|
||||
|
||||
/// Bring the window to front and focus.
|
||||
|
||||
@ -3,6 +3,7 @@ source: crates/tests/acl/src/lib.rs
|
||||
expression: resolved
|
||||
---
|
||||
Resolved {
|
||||
has_app_acl: false,
|
||||
allowed_commands: {
|
||||
"plugin:os|spawn": [
|
||||
ResolvedCommand {
|
||||
|
||||
@ -54,8 +54,8 @@
|
||||
"eslint-config-prettier": "10.1.8",
|
||||
"eslint-plugin-security": "3.0.1",
|
||||
"fast-glob": "3.3.3",
|
||||
"globals": "^16.2.0",
|
||||
"rollup": "4.54.0",
|
||||
"globals": "^17.0.0",
|
||||
"rollup": "4.55.1",
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.8.3",
|
||||
"typescript-eslint": "^8.34.1"
|
||||
|
||||
@ -20,7 +20,7 @@ if (globalThis.navigator?.userAgent?.includes('Deno')) {
|
||||
}
|
||||
// Even if started by a package manager, the binary will be NodeJS.
|
||||
// Some distribution still use "nodejs" as the binary name.
|
||||
else if (binStem.match(/(nodejs|node|bun)\-?([0-9]*)*$/g)) {
|
||||
else if (binStem.match(/(nodejs|node|bun|electron)\-?([0-9]*)*$/g)) {
|
||||
const managerStem = process.env.npm_execpath
|
||||
? path.parse(process.env.npm_execpath).name.toLowerCase()
|
||||
: null
|
||||
|
||||
243
pnpm-lock.yaml
243
pnpm-lock.yaml
@ -63,10 +63,10 @@ importers:
|
||||
version: 9.29.0
|
||||
'@rollup/plugin-terser':
|
||||
specifier: 0.4.4
|
||||
version: 0.4.4(rollup@4.54.0)
|
||||
version: 0.4.4(rollup@4.55.1)
|
||||
'@rollup/plugin-typescript':
|
||||
specifier: 12.3.0
|
||||
version: 12.3.0(rollup@4.54.0)(tslib@2.8.1)(typescript@5.8.3)
|
||||
version: 12.3.0(rollup@4.55.1)(tslib@2.8.1)(typescript@5.8.3)
|
||||
'@types/eslint':
|
||||
specifier: ^9.6.1
|
||||
version: 9.6.1
|
||||
@ -86,11 +86,11 @@ importers:
|
||||
specifier: 3.3.3
|
||||
version: 3.3.3
|
||||
globals:
|
||||
specifier: ^16.2.0
|
||||
version: 16.2.0
|
||||
specifier: ^17.0.0
|
||||
version: 17.0.0
|
||||
rollup:
|
||||
specifier: 4.54.0
|
||||
version: 4.54.0
|
||||
specifier: 4.55.1
|
||||
version: 4.55.1
|
||||
tslib:
|
||||
specifier: ^2.8.1
|
||||
version: 2.8.1
|
||||
@ -1125,113 +1125,128 @@ packages:
|
||||
rollup:
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-android-arm-eabi@4.54.0':
|
||||
resolution: {integrity: sha512-OywsdRHrFvCdvsewAInDKCNyR3laPA2mc9bRYJ6LBp5IyvF3fvXbbNR0bSzHlZVFtn6E0xw2oZlyjg4rKCVcng==}
|
||||
'@rollup/rollup-android-arm-eabi@4.55.1':
|
||||
resolution: {integrity: sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@rollup/rollup-android-arm64@4.54.0':
|
||||
resolution: {integrity: sha512-Skx39Uv+u7H224Af+bDgNinitlmHyQX1K/atIA32JP3JQw6hVODX5tkbi2zof/E69M1qH2UoN3Xdxgs90mmNYw==}
|
||||
'@rollup/rollup-android-arm64@4.55.1':
|
||||
resolution: {integrity: sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@rollup/rollup-darwin-arm64@4.54.0':
|
||||
resolution: {integrity: sha512-k43D4qta/+6Fq+nCDhhv9yP2HdeKeP56QrUUTW7E6PhZP1US6NDqpJj4MY0jBHlJivVJD5P8NxrjuobZBJTCRw==}
|
||||
'@rollup/rollup-darwin-arm64@4.55.1':
|
||||
resolution: {integrity: sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@rollup/rollup-darwin-x64@4.54.0':
|
||||
resolution: {integrity: sha512-cOo7biqwkpawslEfox5Vs8/qj83M/aZCSSNIWpVzfU2CYHa2G3P1UN5WF01RdTHSgCkri7XOlTdtk17BezlV3A==}
|
||||
'@rollup/rollup-darwin-x64@4.55.1':
|
||||
resolution: {integrity: sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@rollup/rollup-freebsd-arm64@4.54.0':
|
||||
resolution: {integrity: sha512-miSvuFkmvFbgJ1BevMa4CPCFt5MPGw094knM64W9I0giUIMMmRYcGW/JWZDriaw/k1kOBtsWh1z6nIFV1vPNtA==}
|
||||
'@rollup/rollup-freebsd-arm64@4.55.1':
|
||||
resolution: {integrity: sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==}
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
|
||||
'@rollup/rollup-freebsd-x64@4.54.0':
|
||||
resolution: {integrity: sha512-KGXIs55+b/ZfZsq9aR026tmr/+7tq6VG6MsnrvF4H8VhwflTIuYh+LFUlIsRdQSgrgmtM3fVATzEAj4hBQlaqQ==}
|
||||
'@rollup/rollup-freebsd-x64@4.55.1':
|
||||
resolution: {integrity: sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@rollup/rollup-linux-arm-gnueabihf@4.54.0':
|
||||
resolution: {integrity: sha512-EHMUcDwhtdRGlXZsGSIuXSYwD5kOT9NVnx9sqzYiwAc91wfYOE1g1djOEDseZJKKqtHAHGwnGPQu3kytmfaXLQ==}
|
||||
'@rollup/rollup-linux-arm-gnueabihf@4.55.1':
|
||||
resolution: {integrity: sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.54.0':
|
||||
resolution: {integrity: sha512-+pBrqEjaakN2ySv5RVrj/qLytYhPKEUwk+e3SFU5jTLHIcAtqh2rLrd/OkbNuHJpsBgxsD8ccJt5ga/SeG0JmA==}
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.55.1':
|
||||
resolution: {integrity: sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-arm64-gnu@4.54.0':
|
||||
resolution: {integrity: sha512-NSqc7rE9wuUaRBsBp5ckQ5CVz5aIRKCwsoa6WMF7G01sX3/qHUw/z4pv+D+ahL1EIKy6Enpcnz1RY8pf7bjwng==}
|
||||
'@rollup/rollup-linux-arm64-gnu@4.55.1':
|
||||
resolution: {integrity: sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.54.0':
|
||||
resolution: {integrity: sha512-gr5vDbg3Bakga5kbdpqx81m2n9IX8M6gIMlQQIXiLTNeQW6CucvuInJ91EuCJ/JYvc+rcLLsDFcfAD1K7fMofg==}
|
||||
'@rollup/rollup-linux-arm64-musl@4.55.1':
|
||||
resolution: {integrity: sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-loong64-gnu@4.54.0':
|
||||
resolution: {integrity: sha512-gsrtB1NA3ZYj2vq0Rzkylo9ylCtW/PhpLEivlgWe0bpgtX5+9j9EZa0wtZiCjgu6zmSeZWyI/e2YRX1URozpIw==}
|
||||
'@rollup/rollup-linux-loong64-gnu@4.55.1':
|
||||
resolution: {integrity: sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-ppc64-gnu@4.54.0':
|
||||
resolution: {integrity: sha512-y3qNOfTBStmFNq+t4s7Tmc9hW2ENtPg8FeUD/VShI7rKxNW7O4fFeaYbMsd3tpFlIg1Q8IapFgy7Q9i2BqeBvA==}
|
||||
'@rollup/rollup-linux-loong64-musl@4.55.1':
|
||||
resolution: {integrity: sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-ppc64-gnu@4.55.1':
|
||||
resolution: {integrity: sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.54.0':
|
||||
resolution: {integrity: sha512-89sepv7h2lIVPsFma8iwmccN7Yjjtgz0Rj/Ou6fEqg3HDhpCa+Et+YSufy27i6b0Wav69Qv4WBNl3Rs6pwhebQ==}
|
||||
'@rollup/rollup-linux-ppc64-musl@4.55.1':
|
||||
resolution: {integrity: sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.55.1':
|
||||
resolution: {integrity: sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-musl@4.54.0':
|
||||
resolution: {integrity: sha512-ZcU77ieh0M2Q8Ur7D5X7KvK+UxbXeDHwiOt/CPSBTI1fBmeDMivW0dPkdqkT4rOgDjrDDBUed9x4EgraIKoR2A==}
|
||||
'@rollup/rollup-linux-riscv64-musl@4.55.1':
|
||||
resolution: {integrity: sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-s390x-gnu@4.54.0':
|
||||
resolution: {integrity: sha512-2AdWy5RdDF5+4YfG/YesGDDtbyJlC9LHmL6rZw6FurBJ5n4vFGupsOBGfwMRjBYH7qRQowT8D/U4LoSvVwOhSQ==}
|
||||
'@rollup/rollup-linux-s390x-gnu@4.55.1':
|
||||
resolution: {integrity: sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-x64-gnu@4.54.0':
|
||||
resolution: {integrity: sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ==}
|
||||
'@rollup/rollup-linux-x64-gnu@4.55.1':
|
||||
resolution: {integrity: sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.54.0':
|
||||
resolution: {integrity: sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw==}
|
||||
'@rollup/rollup-linux-x64-musl@4.55.1':
|
||||
resolution: {integrity: sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-openharmony-arm64@4.54.0':
|
||||
resolution: {integrity: sha512-huT3fd0iC7jigGh7n3q/+lfPcXxBi+om/Rs3yiFxjvSxbSB6aohDFXbWvlspaqjeOh+hx7DDHS+5Es5qRkWkZg==}
|
||||
'@rollup/rollup-openbsd-x64@4.55.1':
|
||||
resolution: {integrity: sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==}
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
|
||||
'@rollup/rollup-openharmony-arm64@4.55.1':
|
||||
resolution: {integrity: sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==}
|
||||
cpu: [arm64]
|
||||
os: [openharmony]
|
||||
|
||||
'@rollup/rollup-win32-arm64-msvc@4.54.0':
|
||||
resolution: {integrity: sha512-c2V0W1bsKIKfbLMBu/WGBz6Yci8nJ/ZJdheE0EwB73N3MvHYKiKGs3mVilX4Gs70eGeDaMqEob25Tw2Gb9Nqyw==}
|
||||
'@rollup/rollup-win32-arm64-msvc@4.55.1':
|
||||
resolution: {integrity: sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@rollup/rollup-win32-ia32-msvc@4.54.0':
|
||||
resolution: {integrity: sha512-woEHgqQqDCkAzrDhvDipnSirm5vxUXtSKDYTVpZG3nUdW/VVB5VdCYA2iReSj/u3yCZzXID4kuKG7OynPnB3WQ==}
|
||||
'@rollup/rollup-win32-ia32-msvc@4.55.1':
|
||||
resolution: {integrity: sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@rollup/rollup-win32-x64-gnu@4.54.0':
|
||||
resolution: {integrity: sha512-dzAc53LOuFvHwbCEOS0rPbXp6SIhAf2txMP5p6mGyOXXw5mWY8NGGbPMPrs4P1WItkfApDathBj/NzMLUZ9rtQ==}
|
||||
'@rollup/rollup-win32-x64-gnu@4.55.1':
|
||||
resolution: {integrity: sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@rollup/rollup-win32-x64-msvc@4.54.0':
|
||||
resolution: {integrity: sha512-hYT5d3YNdSh3mbCU1gwQyPgQd3T2ne0A3KG8KSBdav5TiBg6eInVmV+TeR5uHufiIgSFg0XsOWGW5/RhNcSvPg==}
|
||||
'@rollup/rollup-win32-x64-msvc@4.55.1':
|
||||
resolution: {integrity: sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
@ -1858,8 +1873,8 @@ packages:
|
||||
resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
globals@16.2.0:
|
||||
resolution: {integrity: sha512-O+7l9tPdHCU320IigZZPj5zmRCFG9xHmx9cU8FqU2Rp+JN714seHV+2S9+JslCpY4gJwU2vOGox0wzgae/MCEg==}
|
||||
globals@17.0.0:
|
||||
resolution: {integrity: sha512-gv5BeD2EssA793rlFWVPMMCqefTlpusw6/2TbAVMy0FzcG8wKJn4O+NqJ4+XWmmwrayJgw5TzrmWjFgmz1XPqw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
graphemer@1.4.0:
|
||||
@ -2151,8 +2166,8 @@ packages:
|
||||
resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
|
||||
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
|
||||
|
||||
rollup@4.54.0:
|
||||
resolution: {integrity: sha512-3nk8Y3a9Ea8szgKhinMlGMhGMw89mqule3KWczxhIzqudyHdCIOHw8WJlj/r329fACjKLEh13ZSk7oE22kyeIw==}
|
||||
rollup@4.55.1:
|
||||
resolution: {integrity: sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==}
|
||||
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
|
||||
hasBin: true
|
||||
|
||||
@ -3290,95 +3305,104 @@ snapshots:
|
||||
dependencies:
|
||||
quansync: 0.2.10
|
||||
|
||||
'@rollup/plugin-terser@0.4.4(rollup@4.54.0)':
|
||||
'@rollup/plugin-terser@0.4.4(rollup@4.55.1)':
|
||||
dependencies:
|
||||
serialize-javascript: 6.0.2
|
||||
smob: 1.5.0
|
||||
terser: 5.43.1
|
||||
optionalDependencies:
|
||||
rollup: 4.54.0
|
||||
rollup: 4.55.1
|
||||
|
||||
'@rollup/plugin-typescript@12.3.0(rollup@4.54.0)(tslib@2.8.1)(typescript@5.8.3)':
|
||||
'@rollup/plugin-typescript@12.3.0(rollup@4.55.1)(tslib@2.8.1)(typescript@5.8.3)':
|
||||
dependencies:
|
||||
'@rollup/pluginutils': 5.2.0(rollup@4.54.0)
|
||||
'@rollup/pluginutils': 5.2.0(rollup@4.55.1)
|
||||
resolve: 1.22.10
|
||||
typescript: 5.8.3
|
||||
optionalDependencies:
|
||||
rollup: 4.54.0
|
||||
rollup: 4.55.1
|
||||
tslib: 2.8.1
|
||||
|
||||
'@rollup/pluginutils@5.2.0(rollup@4.54.0)':
|
||||
'@rollup/pluginutils@5.2.0(rollup@4.55.1)':
|
||||
dependencies:
|
||||
'@types/estree': 1.0.8
|
||||
estree-walker: 2.0.2
|
||||
picomatch: 4.0.3
|
||||
optionalDependencies:
|
||||
rollup: 4.54.0
|
||||
rollup: 4.55.1
|
||||
|
||||
'@rollup/rollup-android-arm-eabi@4.54.0':
|
||||
'@rollup/rollup-android-arm-eabi@4.55.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-android-arm64@4.54.0':
|
||||
'@rollup/rollup-android-arm64@4.55.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-darwin-arm64@4.54.0':
|
||||
'@rollup/rollup-darwin-arm64@4.55.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-darwin-x64@4.54.0':
|
||||
'@rollup/rollup-darwin-x64@4.55.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-freebsd-arm64@4.54.0':
|
||||
'@rollup/rollup-freebsd-arm64@4.55.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-freebsd-x64@4.54.0':
|
||||
'@rollup/rollup-freebsd-x64@4.55.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm-gnueabihf@4.54.0':
|
||||
'@rollup/rollup-linux-arm-gnueabihf@4.55.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.54.0':
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.55.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm64-gnu@4.54.0':
|
||||
'@rollup/rollup-linux-arm64-gnu@4.55.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.54.0':
|
||||
'@rollup/rollup-linux-arm64-musl@4.55.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-loong64-gnu@4.54.0':
|
||||
'@rollup/rollup-linux-loong64-gnu@4.55.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-ppc64-gnu@4.54.0':
|
||||
'@rollup/rollup-linux-loong64-musl@4.55.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.54.0':
|
||||
'@rollup/rollup-linux-ppc64-gnu@4.55.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-riscv64-musl@4.54.0':
|
||||
'@rollup/rollup-linux-ppc64-musl@4.55.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-s390x-gnu@4.54.0':
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.55.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-x64-gnu@4.54.0':
|
||||
'@rollup/rollup-linux-riscv64-musl@4.55.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.54.0':
|
||||
'@rollup/rollup-linux-s390x-gnu@4.55.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-openharmony-arm64@4.54.0':
|
||||
'@rollup/rollup-linux-x64-gnu@4.55.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-arm64-msvc@4.54.0':
|
||||
'@rollup/rollup-linux-x64-musl@4.55.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-ia32-msvc@4.54.0':
|
||||
'@rollup/rollup-openbsd-x64@4.55.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-x64-gnu@4.54.0':
|
||||
'@rollup/rollup-openharmony-arm64@4.55.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-x64-msvc@4.54.0':
|
||||
'@rollup/rollup-win32-arm64-msvc@4.55.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-ia32-msvc@4.55.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-x64-gnu@4.55.1':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-x64-msvc@4.55.1':
|
||||
optional: true
|
||||
|
||||
'@standard-schema/spec@1.0.0': {}
|
||||
@ -4128,7 +4152,7 @@ snapshots:
|
||||
|
||||
globals@15.15.0: {}
|
||||
|
||||
globals@16.2.0: {}
|
||||
globals@17.0.0: {}
|
||||
|
||||
graphemer@1.4.0: {}
|
||||
|
||||
@ -4385,32 +4409,35 @@ snapshots:
|
||||
|
||||
reusify@1.1.0: {}
|
||||
|
||||
rollup@4.54.0:
|
||||
rollup@4.55.1:
|
||||
dependencies:
|
||||
'@types/estree': 1.0.8
|
||||
optionalDependencies:
|
||||
'@rollup/rollup-android-arm-eabi': 4.54.0
|
||||
'@rollup/rollup-android-arm64': 4.54.0
|
||||
'@rollup/rollup-darwin-arm64': 4.54.0
|
||||
'@rollup/rollup-darwin-x64': 4.54.0
|
||||
'@rollup/rollup-freebsd-arm64': 4.54.0
|
||||
'@rollup/rollup-freebsd-x64': 4.54.0
|
||||
'@rollup/rollup-linux-arm-gnueabihf': 4.54.0
|
||||
'@rollup/rollup-linux-arm-musleabihf': 4.54.0
|
||||
'@rollup/rollup-linux-arm64-gnu': 4.54.0
|
||||
'@rollup/rollup-linux-arm64-musl': 4.54.0
|
||||
'@rollup/rollup-linux-loong64-gnu': 4.54.0
|
||||
'@rollup/rollup-linux-ppc64-gnu': 4.54.0
|
||||
'@rollup/rollup-linux-riscv64-gnu': 4.54.0
|
||||
'@rollup/rollup-linux-riscv64-musl': 4.54.0
|
||||
'@rollup/rollup-linux-s390x-gnu': 4.54.0
|
||||
'@rollup/rollup-linux-x64-gnu': 4.54.0
|
||||
'@rollup/rollup-linux-x64-musl': 4.54.0
|
||||
'@rollup/rollup-openharmony-arm64': 4.54.0
|
||||
'@rollup/rollup-win32-arm64-msvc': 4.54.0
|
||||
'@rollup/rollup-win32-ia32-msvc': 4.54.0
|
||||
'@rollup/rollup-win32-x64-gnu': 4.54.0
|
||||
'@rollup/rollup-win32-x64-msvc': 4.54.0
|
||||
'@rollup/rollup-android-arm-eabi': 4.55.1
|
||||
'@rollup/rollup-android-arm64': 4.55.1
|
||||
'@rollup/rollup-darwin-arm64': 4.55.1
|
||||
'@rollup/rollup-darwin-x64': 4.55.1
|
||||
'@rollup/rollup-freebsd-arm64': 4.55.1
|
||||
'@rollup/rollup-freebsd-x64': 4.55.1
|
||||
'@rollup/rollup-linux-arm-gnueabihf': 4.55.1
|
||||
'@rollup/rollup-linux-arm-musleabihf': 4.55.1
|
||||
'@rollup/rollup-linux-arm64-gnu': 4.55.1
|
||||
'@rollup/rollup-linux-arm64-musl': 4.55.1
|
||||
'@rollup/rollup-linux-loong64-gnu': 4.55.1
|
||||
'@rollup/rollup-linux-loong64-musl': 4.55.1
|
||||
'@rollup/rollup-linux-ppc64-gnu': 4.55.1
|
||||
'@rollup/rollup-linux-ppc64-musl': 4.55.1
|
||||
'@rollup/rollup-linux-riscv64-gnu': 4.55.1
|
||||
'@rollup/rollup-linux-riscv64-musl': 4.55.1
|
||||
'@rollup/rollup-linux-s390x-gnu': 4.55.1
|
||||
'@rollup/rollup-linux-x64-gnu': 4.55.1
|
||||
'@rollup/rollup-linux-x64-musl': 4.55.1
|
||||
'@rollup/rollup-openbsd-x64': 4.55.1
|
||||
'@rollup/rollup-openharmony-arm64': 4.55.1
|
||||
'@rollup/rollup-win32-arm64-msvc': 4.55.1
|
||||
'@rollup/rollup-win32-ia32-msvc': 4.55.1
|
||||
'@rollup/rollup-win32-x64-gnu': 4.55.1
|
||||
'@rollup/rollup-win32-x64-msvc': 4.55.1
|
||||
fsevents: 2.3.3
|
||||
|
||||
run-parallel@1.2.0:
|
||||
@ -4652,7 +4679,7 @@ snapshots:
|
||||
fdir: 6.5.0(picomatch@4.0.3)
|
||||
picomatch: 4.0.3
|
||||
postcss: 8.5.6
|
||||
rollup: 4.54.0
|
||||
rollup: 4.55.1
|
||||
tinyglobby: 0.2.15
|
||||
optionalDependencies:
|
||||
'@types/node': 24.10.0
|
||||
|
||||
Loading…
Reference in New Issue
Block a user