mirror of
https://github.com/tauri-apps/tauri.git
synced 2026-04-11 10:43:31 +02:00
Compare commits
238 Commits
@tauri-app
...
fix/wait-w
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f1b6e9314e | ||
|
|
e15f665efc | ||
|
|
479cee3d36 | ||
|
|
09c19932d2 | ||
|
|
4221124c4e | ||
|
|
b985eaf0a2 | ||
|
|
c84b162374 | ||
|
|
4f75bf5bdb | ||
|
|
b5c549d189 | ||
|
|
208f4bcadc | ||
|
|
f0662e41f4 | ||
|
|
dfacb656d2 | ||
|
|
db03f00693 | ||
|
|
a60a383360 | ||
|
|
aa8661acfd | ||
|
|
e045fe32c9 | ||
|
|
197da6fe78 | ||
|
|
94b77b36e3 | ||
|
|
527bf0031e | ||
|
|
35aa7e1218 | ||
|
|
23b9da75b9 | ||
|
|
8a8c1f9f3b | ||
|
|
50ebddaa2d | ||
|
|
568efb4568 | ||
|
|
6ce10ab773 | ||
|
|
039f44b7b1 | ||
|
|
00dfc32a2d | ||
|
|
76cbeef208 | ||
|
|
267368fd4f | ||
|
|
4e00b27913 | ||
|
|
766bccc341 | ||
|
|
31becbd1d1 | ||
|
|
da2a6ae5e3 | ||
|
|
87fdc3b9cd | ||
|
|
30e76c7d3a | ||
|
|
85b1912529 | ||
|
|
82da4f17f5 | ||
|
|
977c4b496c | ||
|
|
48b12b4404 | ||
|
|
9356fa15d8 | ||
|
|
2dccfab532 | ||
|
|
5d3687e8c3 | ||
|
|
0cf2d9933f | ||
|
|
1734273bbe | ||
|
|
690146e311 | ||
|
|
f888502fd2 | ||
|
|
577c7ffc45 | ||
|
|
82406c61e0 | ||
|
|
07953fb9c3 | ||
|
|
8d994f60fe | ||
|
|
8a1d490820 | ||
|
|
89c6e436ea | ||
|
|
b0babb6df1 | ||
|
|
b8f86669ab | ||
|
|
7ed877a0ae | ||
|
|
ea36294cbc | ||
|
|
0d39ff6b09 | ||
|
|
ad3fd3890f | ||
|
|
3752fed282 | ||
|
|
b072e2b296 | ||
|
|
0802529031 | ||
|
|
66e6325f43 | ||
|
|
0aa48fb9e4 | ||
|
|
628f4a97e4 | ||
|
|
fca5154e7a | ||
|
|
fbd57a1afd | ||
|
|
dd4f13ce4b | ||
|
|
7b14531f24 | ||
|
|
7a86e0f8a1 | ||
|
|
c1cd0a2ddb | ||
|
|
073dbc3953 | ||
|
|
47df696dfb | ||
|
|
9ea76503dc | ||
|
|
bb5faa21f4 | ||
|
|
b32153b437 | ||
|
|
c71755fd5f | ||
|
|
7b81825144 | ||
|
|
ebd3dcb92f | ||
|
|
80dccb6a2e | ||
|
|
cf0b3588a3 | ||
|
|
b8c0d7e402 | ||
|
|
e4982dff73 | ||
|
|
8cf662e34b | ||
|
|
b154826881 | ||
|
|
dade232592 | ||
|
|
aa6b4d4edf | ||
|
|
794af778e4 | ||
|
|
4e22ae29d3 | ||
|
|
4ae14bf2f2 | ||
|
|
f805061d11 | ||
|
|
30beb6fee7 | ||
|
|
22c7a877e3 | ||
|
|
2138bbc212 | ||
|
|
5c2b3b8b65 | ||
|
|
dd13728334 | ||
|
|
f235ec0113 | ||
|
|
f182b0bb93 | ||
|
|
a851b6597f | ||
|
|
be31675fbc | ||
|
|
dea8bbf6cd | ||
|
|
be3a79c864 | ||
|
|
ba42a1f553 | ||
|
|
1cd8f55eed | ||
|
|
8603e42a6b | ||
|
|
c32bd722d3 | ||
|
|
bcdd510254 | ||
|
|
71cb1e26d7 | ||
|
|
b459f1d405 | ||
|
|
8cc0067165 | ||
|
|
f2c94aaca0 | ||
|
|
cefefa930b | ||
|
|
4a01299e31 | ||
|
|
5a23146566 | ||
|
|
4062e49914 | ||
|
|
a483ba7c27 | ||
|
|
f981a5ee8b | ||
|
|
2b960dfd9f | ||
|
|
eec08a18b6 | ||
|
|
35018eed02 | ||
|
|
de7f34bff4 | ||
|
|
72df2e4a04 | ||
|
|
0d1446857c | ||
|
|
658e5f5d1d | ||
|
|
7930dde85c | ||
|
|
b05f82d35b | ||
|
|
51bcafe323 | ||
|
|
013f8f6523 | ||
|
|
5591a4f0b4 | ||
|
|
2fa33d5c44 | ||
|
|
cedb24d494 | ||
|
|
30f5a1553d | ||
|
|
08de8a172b | ||
|
|
c108024257 | ||
|
|
dc90cd3919 | ||
|
|
0ec71a844c | ||
|
|
0c4700e990 | ||
|
|
b83921226c | ||
|
|
3cc4ad3c38 | ||
|
|
d91bfa5cb9 | ||
|
|
f67a4a6bfe | ||
|
|
d8059bad3c | ||
|
|
be2e6b85fe | ||
|
|
b9ee806724 | ||
|
|
339a075e33 | ||
|
|
93124ad2eb | ||
|
|
3a74dc8f34 | ||
|
|
3626b7a92b | ||
|
|
eea12c196e | ||
|
|
4ce5c74ab4 | ||
|
|
2d029a9f53 | ||
|
|
f268b3dbdf | ||
|
|
755533c518 | ||
|
|
dc78dfecab | ||
|
|
f98598817c | ||
|
|
060de5bbdd | ||
|
|
c698a6d6f3 | ||
|
|
20c1906912 | ||
|
|
3fb8d7ca6b | ||
|
|
55ffa23c9e | ||
|
|
cab7f76d01 | ||
|
|
e103e87f15 | ||
|
|
bca02967a9 | ||
|
|
887db0813f | ||
|
|
4f26dcf309 | ||
|
|
4bffc326ea | ||
|
|
b859dc43fc | ||
|
|
9332132239 | ||
|
|
22e9bf74a4 | ||
|
|
b495fe0fdc | ||
|
|
7d618f12d8 | ||
|
|
385a41dea2 | ||
|
|
955832e56b | ||
|
|
c116dfcdee | ||
|
|
d6520a21ce | ||
|
|
ab81adb71b | ||
|
|
6e417c9435 | ||
|
|
ddc469367a | ||
|
|
d7b998fe71 | ||
|
|
d9a07e66af | ||
|
|
0adeb4e7c5 | ||
|
|
70d8557cc3 | ||
|
|
95fc3cd424 | ||
|
|
4633705da7 | ||
|
|
3f680588cd | ||
|
|
7d8252679d | ||
|
|
ee95c1b1ed | ||
|
|
741e44b45c | ||
|
|
8e9339e880 | ||
|
|
053b57c1df | ||
|
|
b6a56f3616 | ||
|
|
11945e561c | ||
|
|
b6ad316460 | ||
|
|
5eba0785c4 | ||
|
|
6038f09d85 | ||
|
|
e3b0260871 | ||
|
|
a6ada76a9f | ||
|
|
bfc71e845b | ||
|
|
0a11b8741a | ||
|
|
6b70fbcc84 | ||
|
|
e9c9c4d6f6 | ||
|
|
abdd558075 | ||
|
|
3dbcbe7685 | ||
|
|
a2d36b8c34 | ||
|
|
5a3647bdfe | ||
|
|
477e9c0496 | ||
|
|
82d634f4a9 | ||
|
|
8e9134c4a2 | ||
|
|
dc1997b77d | ||
|
|
1a86974aa3 | ||
|
|
fb294af8e3 | ||
|
|
46c7b16111 | ||
|
|
9dac2863af | ||
|
|
9a9d1205b0 | ||
|
|
27096cdc05 | ||
|
|
6cbfc4878d | ||
|
|
f5a59b93bf | ||
|
|
5432752e51 | ||
|
|
bf912b8e08 | ||
|
|
9a30bed98c | ||
|
|
9d02c18ac2 | ||
|
|
de8600b4d9 | ||
|
|
0ea8894579 | ||
|
|
fbe7c9ead7 | ||
|
|
b8eb28877f | ||
|
|
90c6546faf | ||
|
|
4ed2ab76e2 | ||
|
|
bc43c738ba | ||
|
|
0b79af7114 | ||
|
|
a70e690fe7 | ||
|
|
72748cc45c | ||
|
|
cf771bf69a | ||
|
|
07ccdc499c | ||
|
|
d2c8f0eb5c | ||
|
|
b643dcc1c4 | ||
|
|
cd7d08b63f | ||
|
|
4c3f047735 | ||
|
|
61e69db9e4 | ||
|
|
75d56e8364 |
5
.changes/bundler-appimage-arch-env.md
Normal file
5
.changes/bundler-appimage-arch-env.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
tauri-bundler: "patch:bug"
|
||||
---
|
||||
|
||||
The bundler now sets the `ARCH` env var to the current build target to prevent potential issues with `appimagetool`'s auto-detection.
|
||||
5
.changes/change-pr-13288.md
Normal file
5
.changes/change-pr-13288.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"tauri": 'patch:bug'
|
||||
---
|
||||
|
||||
Prevent the JavaScript runtime crashing when channel events fire in a webview that no longer has callbacks for the channel.
|
||||
@@ -4,7 +4,7 @@
|
||||
"feat": "New Features",
|
||||
"enhance": "Enhancements",
|
||||
"bug": "Bug Fixes",
|
||||
"pref": "Performance Improvements",
|
||||
"perf": "Performance Improvements",
|
||||
"changes": "What's Changed",
|
||||
"sec": "Security fixes",
|
||||
"deps": "Dependencies",
|
||||
|
||||
7
.changes/feat-webview-auto-resize.md
Normal file
7
.changes/feat-webview-auto-resize.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"tauri": "minor:feat"
|
||||
"@tauri-apps/api": "minor:feat"
|
||||
---
|
||||
|
||||
Expose the `setAutoResize` API for webviews in `@tauri-apps/api`.
|
||||
|
||||
5
.changes/fix-custom-signer-uninstaller.md
Normal file
5
.changes/fix-custom-signer-uninstaller.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"tauri-bundler": patch:bug
|
||||
---
|
||||
|
||||
Fix custom Windows sign command failing to sign app uninstaller if it references relative paths.
|
||||
6
.changes/fix-frontenddir-target-error.md
Normal file
6
.changes/fix-frontenddir-target-error.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"tauri-cli": "patch:bug"
|
||||
"@tauri-apps/cli": "patch:bug"
|
||||
---
|
||||
|
||||
fix: allow the target directory to be inside frontendDir as long as it is not the Rust target directory inside frontendDir.
|
||||
5
.changes/fix-ios-register-listener.md
Normal file
5
.changes/fix-ios-register-listener.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"tauri": patch:bug
|
||||
---
|
||||
|
||||
Fixes multiple event listeners registration for iOS plugins.
|
||||
6
.changes/fix-path-join-error.md
Normal file
6
.changes/fix-path-join-error.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"tauri": "minor:bug"
|
||||
"@tauri-apps/api": "minor:bug"
|
||||
---
|
||||
|
||||
Fixed path joining behavior where `path.join('', 'a')` incorrectly returns "/a" instead of "a".
|
||||
5
.changes/fix-prevent-overflow-monitor-check.md
Normal file
5
.changes/fix-prevent-overflow-monitor-check.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"tauri-runtime-wry": patch:bug
|
||||
---
|
||||
|
||||
Fix monitor check on the window prevent overflow implementation.
|
||||
5
.changes/fix-tray-get-by-id.md
Normal file
5
.changes/fix-tray-get-by-id.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"tauri": patch:bug
|
||||
---
|
||||
|
||||
Fix `TrayIcon.getById` returning a new resource ID instead of reusing a previously created id from `TrayIcon.new`.
|
||||
5
.changes/fix-webview-proxy-url.md
Normal file
5
.changes/fix-webview-proxy-url.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'tauri': 'patch:bug'
|
||||
---
|
||||
|
||||
Fix JavaScript API `Webview.proxyUrl` had no effect when used in the `Webview` constructor
|
||||
5
.changes/monitor-workarea-js.md
Normal file
5
.changes/monitor-workarea-js.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tauri-apps/api": "minor:feat"
|
||||
---
|
||||
|
||||
Add `Monitor.workArea` field.
|
||||
6
.changes/monitor-workarea-rust.md
Normal file
6
.changes/monitor-workarea-rust.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"tauri": "minor:feat"
|
||||
---
|
||||
|
||||
Add `Monitor::work_area` getter
|
||||
|
||||
6
.changes/physical-logical-rect.md
Normal file
6
.changes/physical-logical-rect.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"tauri": "minor:feat"
|
||||
---
|
||||
|
||||
Added `tauri::PhysicalRect` and `tauri::LogicalRect` types.
|
||||
|
||||
5
.changes/service-worker-allowed-http-header.md
Normal file
5
.changes/service-worker-allowed-http-header.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"tauri-utils": 'minor:feat'
|
||||
"tauri": 'minor:feat'
|
||||
---
|
||||
Adds the option to configure the HTTP `Service-Worker-Allowed` response header in `app > security > headers`
|
||||
6
.changes/transform-callback.md
Normal file
6
.changes/transform-callback.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@tauri-apps/api": minor:changes
|
||||
"tauri": minor:changes
|
||||
---
|
||||
|
||||
`transformCallback` now registers the callbacks inside `window.__TAURI_INTERNALS__.callbacks` instead of directly on `window['_{id}']`
|
||||
6
.changes/unlisten-race-condition.md
Normal file
6
.changes/unlisten-race-condition.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@tauri-apps/api": minor:bug
|
||||
"tauri": minor:bug
|
||||
---
|
||||
|
||||
Immediately unregister event listener when the unlisten function is called.
|
||||
7
.github/CONTRIBUTING.md
vendored
7
.github/CONTRIBUTING.md
vendored
@@ -53,7 +53,12 @@ First, [join our Discord server](https://discord.gg/SpmNs4S) and let us know tha
|
||||
|
||||
To set up your machine for development, follow the [Tauri setup guide](https://v2.tauri.app/start/prerequisites/) to get all the tools you need to develop Tauri apps. The only additional tool you may need is [PNPM](https://pnpm.io/), it is only required if you are developing the Node CLI or API packages (`packages/cli` and `packages/api`). Next, fork and clone this repo. It is structured as a monorepo, which means that all the various Tauri packages are under the same repository. The development process varies depending on what part of Tauri you are contributing to, see the guides below for per-package instructions.
|
||||
|
||||
Some Tauri packages will be automatically built when running one of the examples. Others, however, will need to be built beforehand. To build these automatically, run the `.scripts/setup.sh` (Linux and macOS) or `.scripts/setup.ps1` (Windows) script. This will install the Rust and Node.js CLI and build the JS API. After that, you should be able to run all the examples. Note that the setup script should be executed from the root folder of the repository in order to run correctly.
|
||||
Some Tauri packages will be automatically built when running one of the examples. Others, however, will need to be built beforehand. To initialize, execute these commands in the repository root:
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
pnpm build
|
||||
```
|
||||
|
||||
### Overview
|
||||
|
||||
|
||||
2
.github/workflows/audit.yml
vendored
2
.github/workflows/audit.yml
vendored
@@ -34,7 +34,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: corepack enable
|
||||
- run: npm i -g --force corepack
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
|
||||
2
.github/workflows/check-generated-files.yml
vendored
2
.github/workflows/check-generated-files.yml
vendored
@@ -44,7 +44,7 @@ jobs:
|
||||
if: needs.changes.outputs.api == 'true'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: corepack enable
|
||||
- run: npm i -g --force corepack
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- run: corepack enable
|
||||
- run: npm i -g --force corepack
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
@@ -73,7 +73,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- run: corepack enable
|
||||
- run: npm i -g --force corepack
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
2
.github/workflows/docker.yml
vendored
2
.github/workflows/docker.yml
vendored
@@ -66,7 +66,7 @@ jobs:
|
||||
with:
|
||||
targets: ${{ matrix.target.name }}
|
||||
|
||||
- run: corepack enable
|
||||
- run: npm i -g --force corepack
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
|
||||
2
.github/workflows/fmt.yml
vendored
2
.github/workflows/fmt.yml
vendored
@@ -26,7 +26,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: corepack enable
|
||||
- run: npm i -g --force corepack
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
|
||||
4
.github/workflows/lint-js.yml
vendored
4
.github/workflows/lint-js.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: corepack enable
|
||||
- run: npm i -g --force corepack
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: corepack enable
|
||||
- run: npm i -g --force corepack
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
|
||||
2
.github/workflows/lint-rust.yml
vendored
2
.github/workflows/lint-rust.yml
vendored
@@ -10,7 +10,7 @@ on:
|
||||
- dev
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/lint-cli.yml'
|
||||
- '.github/workflows/lint-rust.yml'
|
||||
- 'crates/**'
|
||||
|
||||
env:
|
||||
|
||||
34
.github/workflows/publish-cli-js.yml
vendored
34
.github/workflows/publish-cli-js.yml
vendored
@@ -43,15 +43,16 @@ jobs:
|
||||
- host: windows-latest
|
||||
architecture: x64
|
||||
target: aarch64-pc-windows-msvc
|
||||
build: pnpm build --target aarch64-pc-windows-msvc --features native-tls-vendored --cargo-flags="--no-default-features"
|
||||
- host: ubuntu-20.04
|
||||
build: pnpm build --target aarch64-pc-windows-msvc
|
||||
- host: ubuntu-22.04
|
||||
target: x86_64-unknown-linux-gnu
|
||||
docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian
|
||||
build: |
|
||||
npm i -g --force corepack
|
||||
cd packages/cli
|
||||
pnpm build --target x86_64-unknown-linux-gnu
|
||||
strip *.node
|
||||
- host: ubuntu-20.04
|
||||
- host: ubuntu-22.04
|
||||
target: x86_64-unknown-linux-musl
|
||||
docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine
|
||||
build: |
|
||||
@@ -63,14 +64,15 @@ jobs:
|
||||
build: |
|
||||
pnpm build --features native-tls-vendored --target=aarch64-apple-darwin
|
||||
strip -x *.node
|
||||
- host: ubuntu-20.04
|
||||
- host: ubuntu-22.04
|
||||
target: aarch64-unknown-linux-gnu
|
||||
docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian-aarch64
|
||||
build: |
|
||||
npm i -g --force corepack
|
||||
cd packages/cli
|
||||
pnpm build --target aarch64-unknown-linux-gnu
|
||||
aarch64-unknown-linux-gnu-strip *.node
|
||||
- host: ubuntu-20.04
|
||||
- host: ubuntu-22.04
|
||||
architecture: x64
|
||||
target: armv7-unknown-linux-gnueabihf
|
||||
setup: |
|
||||
@@ -79,7 +81,7 @@ jobs:
|
||||
build: |
|
||||
pnpm build --target=armv7-unknown-linux-gnueabihf
|
||||
arm-linux-gnueabihf-strip *.node
|
||||
- host: ubuntu-20.04
|
||||
- host: ubuntu-22.04
|
||||
architecture: x64
|
||||
target: aarch64-unknown-linux-musl
|
||||
docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine
|
||||
@@ -88,11 +90,20 @@ jobs:
|
||||
rustup target add aarch64-unknown-linux-musl
|
||||
pnpm build --target aarch64-unknown-linux-musl
|
||||
/aarch64-linux-musl-cross/bin/aarch64-linux-musl-strip *.node
|
||||
- host: ubuntu-22.04
|
||||
architecture: x64
|
||||
target: riscv64gc-unknown-linux-gnu
|
||||
setup: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install gcc-riscv64-linux-gnu g++-riscv64-linux-gnu -y
|
||||
build: |
|
||||
pnpm build --target=riscv64gc-unknown-linux-gnu
|
||||
riscv64-linux-gnu-strip *.node
|
||||
name: stable - ${{ matrix.settings.target }} - node@20
|
||||
runs-on: ${{ matrix.settings.host }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: corepack enable
|
||||
- run: npm i -g --force corepack
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v4
|
||||
if: ${{ !matrix.settings.docker }}
|
||||
@@ -202,7 +213,7 @@ jobs:
|
||||
runs-on: ${{ matrix.settings.host }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: corepack enable
|
||||
- run: npm i -g --force corepack
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
@@ -233,7 +244,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: corepack enable
|
||||
- run: npm i -g --force corepack
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
@@ -270,7 +281,7 @@ jobs:
|
||||
image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: corepack enable
|
||||
- run: npm i -g --force corepack
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
@@ -308,7 +319,6 @@ jobs:
|
||||
- '20'
|
||||
image:
|
||||
- ghcr.io/napi-rs/napi-rs/nodejs:aarch64-16
|
||||
- ghcr.io/napi-rs/napi-rs/nodejs:armhf-16
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: docker run --rm --privileged multiarch/qemu-user-static:register --reset
|
||||
@@ -361,7 +371,7 @@ jobs:
|
||||
id-token: write # npm provenance
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: corepack enable
|
||||
- run: npm i -g --force corepack
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
|
||||
4
.github/workflows/publish-cli-rs.yml
vendored
4
.github/workflows/publish-cli-rs.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
config:
|
||||
- os: ubuntu-20.04
|
||||
- os: ubuntu-22.04
|
||||
rust_target: x86_64-unknown-linux-gnu
|
||||
ext: ''
|
||||
args: ''
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
- os: windows-latest
|
||||
rust_target: aarch64-pc-windows-msvc
|
||||
ext: '.exe'
|
||||
args: '--no-default-features --features native-tls-vendored'
|
||||
args: ''
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
2
.github/workflows/test-android.yml
vendored
2
.github/workflows/test-android.yml
vendored
@@ -42,7 +42,7 @@ jobs:
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libgtk-3-dev webkit2gtk-4.1
|
||||
|
||||
- run: corepack enable
|
||||
- run: npm i -g --force corepack
|
||||
- name: setup node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
|
||||
3
.github/workflows/test-cli-js.yml
vendored
3
.github/workflows/test-cli-js.yml
vendored
@@ -11,6 +11,7 @@ on:
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/test-cli-js.yml'
|
||||
- 'packages/cli/**'
|
||||
# currently` @tauri-apps/cli` only tests the template
|
||||
- 'crates/tauri-cli/templates/app/**'
|
||||
|
||||
@@ -37,7 +38,7 @@ jobs:
|
||||
- name: install Rust stable
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- run: corepack enable
|
||||
- run: npm i -g --force corepack
|
||||
- name: setup node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -13,6 +13,8 @@ node_modules/
|
||||
|
||||
# .vscode workspace settings file
|
||||
.vscode/settings.json
|
||||
.vscode/launch.json
|
||||
.vscode/tasks.json
|
||||
|
||||
# npm, yarn and bun lock files
|
||||
package-lock.json
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"singleQuote": true,
|
||||
"semi": false,
|
||||
"trailingComma": "none"
|
||||
"trailingComma": "none",
|
||||
"experimentalOperatorPosition": "start"
|
||||
}
|
||||
|
||||
@@ -28,8 +28,8 @@ const ignore = [
|
||||
|
||||
async function checkFile(file) {
|
||||
if (
|
||||
extensions.some((e) => file.endsWith(e)) &&
|
||||
!ignore.some((i) => file.includes(`/${i}/`) || path.basename(file) == i)
|
||||
extensions.some((e) => file.endsWith(e))
|
||||
&& !ignore.some((i) => file.includes(`/${i}/`) || path.basename(file) == i)
|
||||
) {
|
||||
const fileStream = fs.createReadStream(file)
|
||||
const rl = readline.createInterface({
|
||||
@@ -42,11 +42,11 @@ async function checkFile(file) {
|
||||
for await (let line of rl) {
|
||||
// ignore empty lines, allow shebang and bundler license
|
||||
if (
|
||||
line.length === 0 ||
|
||||
line.startsWith('#!') ||
|
||||
line.startsWith('// swift-tools-version:') ||
|
||||
line === bundlerLicense ||
|
||||
line === denoLicense
|
||||
line.length === 0
|
||||
|| line.startsWith('#!')
|
||||
|| line.startsWith('// swift-tools-version:')
|
||||
|| line === bundlerLicense
|
||||
|| line === denoLicense
|
||||
) {
|
||||
continue
|
||||
}
|
||||
|
||||
1619
Cargo.lock
generated
1619
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -70,3 +70,4 @@ opt-level = "s"
|
||||
[patch.crates-io]
|
||||
schemars_derive = { git = 'https://github.com/tauri-apps/schemars.git', branch = 'feat/preserve-description-newlines' }
|
||||
tauri = { path = "./crates/tauri" }
|
||||
tauri-plugin = { path = "./crates/tauri-plugin" }
|
||||
|
||||
16
README.md
16
README.md
@@ -35,7 +35,7 @@ The list of Tauri's features includes, but is not limited to:
|
||||
- Built-in self updater (desktop only)
|
||||
- System tray icons
|
||||
- Native notifications
|
||||
- [Localhost free (🔥)](https://github.com/tauri-apps/tauri/issues/10510)
|
||||
- Native WebView Protocol (tauri doesn't create a localhost http(s) server to serve the WebView contents)
|
||||
- GitHub action for streamlined CI
|
||||
- VS Code extension
|
||||
|
||||
@@ -43,13 +43,13 @@ The list of Tauri's features includes, but is not limited to:
|
||||
|
||||
Tauri currently supports development and distribution on the following platforms:
|
||||
|
||||
| Platform | Versions |
|
||||
| :---------------- | :-------------------------------------------------------------------------------------------------------------- |
|
||||
| Windows | 7 and above |
|
||||
| macOS | 10.15 and above |
|
||||
| Linux | webkit2gtk 4.0 for Tauri v1 (for example Ubuntu 18.04). webkit2gtk 4.1 for Tauri v2 (for example Ubuntu 22.04). |
|
||||
| iOS/iPadOS (beta) | 9 and above |
|
||||
| Android (beta) | 7 and above |
|
||||
| Platform | Versions |
|
||||
| :--------- | :-------------------------------------------------------------------------------------------------------------- |
|
||||
| Windows | 7 and above |
|
||||
| macOS | 10.15 and above |
|
||||
| Linux | webkit2gtk 4.0 for Tauri v1 (for example Ubuntu 18.04). webkit2gtk 4.1 for Tauri v2 (for example Ubuntu 22.04). |
|
||||
| iOS/iPadOS | 9 and above |
|
||||
| Android | 7 and above (currently 8 and above) |
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica,
|
||||
Arial, sans-serif;
|
||||
font-family:
|
||||
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial,
|
||||
sans-serif;
|
||||
margin: auto;
|
||||
max-width: 38rem;
|
||||
padding: 2rem;
|
||||
|
||||
@@ -1,5 +1,42 @@
|
||||
# Changelog
|
||||
|
||||
## \[2.2.0]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `tauri-utils@2.4.0`
|
||||
- Upgraded to `tauri-codegen@2.2.0`
|
||||
- [`48b12b440`](https://www.github.com/tauri-apps/tauri/commit/48b12b440478937c46fdfef9f9d95194be117020) Update to `tauri-utils@2.4.0`
|
||||
|
||||
## \[2.1.1]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `tauri-utils@2.3.1`
|
||||
- Upgraded to `tauri-codegen@2.1.1`
|
||||
|
||||
## \[2.1.0]
|
||||
|
||||
### New Features
|
||||
|
||||
- [`013f8f652`](https://www.github.com/tauri-apps/tauri/commit/013f8f652302f2d49c5ec0a075582033d8b074fb) ([#12890](https://www.github.com/tauri-apps/tauri/pull/12890) by [@Legend-Master](https://www.github.com/tauri-apps/tauri/../../Legend-Master)) Added `build > removeUnusedCommands` to trigger the build scripts and macros to remove unused commands based on the capabilities you defined. Note this won't be accounting for dynamically added ACLs so make sure to check it when using this.
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
- [`1cd8f55ee`](https://www.github.com/tauri-apps/tauri/commit/1cd8f55eed326d61860fee62ba2d2f4464bdcfcc) ([#13033](https://www.github.com/tauri-apps/tauri/pull/13033) by [@Legend-Master](https://www.github.com/tauri-apps/tauri/../../Legend-Master)) Don't ship global `bundle.global.js` if `app > withGlobalTauri` is set to false
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `tauri-utils@2.3.0`
|
||||
- Upgraded to `tauri-codegen@2.1.0`
|
||||
|
||||
## \[2.0.6]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `tauri-utils@2.2.0`
|
||||
- Upgraded to `tauri-codegen@2.0.5`
|
||||
|
||||
## \[2.0.5]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tauri-build"
|
||||
version = "2.0.5"
|
||||
version = "2.2.0"
|
||||
description = "build time code to pair with https://crates.io/crates/tauri"
|
||||
exclude = ["CHANGELOG.md", "/target"]
|
||||
readme = "README.md"
|
||||
@@ -28,20 +28,20 @@ rustdoc-args = ["--cfg", "docsrs"]
|
||||
[dependencies]
|
||||
anyhow = "1"
|
||||
quote = { version = "1", optional = true }
|
||||
tauri-codegen = { version = "2.0.4", path = "../tauri-codegen", optional = true }
|
||||
tauri-utils = { version = "2.1.1", path = "../tauri-utils", features = [
|
||||
tauri-codegen = { version = "2.2.0", path = "../tauri-codegen", optional = true }
|
||||
tauri-utils = { version = "2.4.0", path = "../tauri-utils", features = [
|
||||
"build",
|
||||
"resources",
|
||||
] }
|
||||
cargo_toml = "0.21"
|
||||
cargo_toml = "0.22"
|
||||
serde = "1"
|
||||
serde_json = "1"
|
||||
heck = "0.5"
|
||||
json-patch = "3"
|
||||
walkdir = "2"
|
||||
tauri-winres = "0.2"
|
||||
tauri-winres = "0.3"
|
||||
semver = "1"
|
||||
dirs = "5"
|
||||
dirs = "6"
|
||||
glob = "0.3"
|
||||
toml = "0.8"
|
||||
# Our code requires at least 0.8.18 so don't simplify this to 0.8
|
||||
|
||||
@@ -11,7 +11,9 @@ use std::{
|
||||
use anyhow::{Context, Result};
|
||||
use tauri_utils::{
|
||||
acl::{
|
||||
capability::Capability, manifest::Manifest, schema::CAPABILITIES_SCHEMA_FOLDER_PATH,
|
||||
capability::Capability,
|
||||
manifest::{Manifest, PermissionFile},
|
||||
schema::CAPABILITIES_SCHEMA_FOLDER_PATH,
|
||||
ACL_MANIFESTS_FILE_NAME, APP_ACL_KEY, CAPABILITIES_FILE_NAME,
|
||||
},
|
||||
platform::Target,
|
||||
@@ -155,11 +157,17 @@ fn read_plugins_manifests() -> Result<BTreeMap<String, Manifest>> {
|
||||
Ok(manifests)
|
||||
}
|
||||
|
||||
struct InlinedPuginsAcl {
|
||||
manifests: BTreeMap<String, Manifest>,
|
||||
permission_files: BTreeMap<String, Vec<PermissionFile>>,
|
||||
}
|
||||
|
||||
fn inline_plugins(
|
||||
out_dir: &Path,
|
||||
inlined_plugins: HashMap<&'static str, InlinedPlugin>,
|
||||
) -> Result<BTreeMap<String, Manifest>> {
|
||||
) -> Result<InlinedPuginsAcl> {
|
||||
let mut acl_manifests = BTreeMap::new();
|
||||
let mut permission_files_map = BTreeMap::new();
|
||||
|
||||
for (name, plugin) in inlined_plugins {
|
||||
let plugin_out_dir = out_dir.join("plugins").join(name);
|
||||
@@ -236,18 +244,29 @@ permissions = [{default_permissions}]
|
||||
)?);
|
||||
}
|
||||
|
||||
permission_files_map.insert(name.into(), permission_files.clone());
|
||||
|
||||
let manifest = tauri_utils::acl::manifest::Manifest::new(permission_files, None);
|
||||
acl_manifests.insert(name.into(), manifest);
|
||||
}
|
||||
|
||||
Ok(acl_manifests)
|
||||
Ok(InlinedPuginsAcl {
|
||||
manifests: acl_manifests,
|
||||
permission_files: permission_files_map,
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct AppManifestAcl {
|
||||
manifest: Manifest,
|
||||
permission_files: Vec<PermissionFile>,
|
||||
}
|
||||
|
||||
fn app_manifest_permissions(
|
||||
out_dir: &Path,
|
||||
manifest: AppManifest,
|
||||
inlined_plugins: &HashMap<&'static str, InlinedPlugin>,
|
||||
) -> Result<Manifest> {
|
||||
) -> Result<AppManifestAcl> {
|
||||
let app_out_dir = out_dir.join("app-manifest");
|
||||
fs::create_dir_all(&app_out_dir)?;
|
||||
let pkg_name = "__app__";
|
||||
@@ -290,6 +309,7 @@ fn app_manifest_permissions(
|
||||
let inlined_plugins_permissions: Vec<_> = inlined_plugins
|
||||
.keys()
|
||||
.map(|name| permissions_root.join(name))
|
||||
.flat_map(|p| p.canonicalize())
|
||||
.collect();
|
||||
|
||||
permission_files.extend(tauri_utils::acl::build::define_permissions(
|
||||
@@ -308,10 +328,10 @@ fn app_manifest_permissions(
|
||||
)?);
|
||||
}
|
||||
|
||||
Ok(tauri_utils::acl::manifest::Manifest::new(
|
||||
permission_files,
|
||||
None,
|
||||
))
|
||||
Ok(AppManifestAcl {
|
||||
permission_files: permission_files.clone(),
|
||||
manifest: tauri_utils::acl::manifest::Manifest::new(permission_files, None),
|
||||
})
|
||||
}
|
||||
|
||||
fn validate_capabilities(
|
||||
@@ -380,19 +400,21 @@ fn validate_capabilities(
|
||||
pub fn build(out_dir: &Path, target: Target, attributes: &Attributes) -> super::Result<()> {
|
||||
let mut acl_manifests = read_plugins_manifests()?;
|
||||
|
||||
let app_manifest = app_manifest_permissions(
|
||||
let app_acl = app_manifest_permissions(
|
||||
out_dir,
|
||||
attributes.app_manifest,
|
||||
&attributes.inlined_plugins,
|
||||
)?;
|
||||
if app_manifest.default_permission.is_some()
|
||||
|| !app_manifest.permission_sets.is_empty()
|
||||
|| !app_manifest.permissions.is_empty()
|
||||
{
|
||||
acl_manifests.insert(APP_ACL_KEY.into(), app_manifest);
|
||||
let has_app_manifest = app_acl.manifest.default_permission.is_some()
|
||||
|| !app_acl.manifest.permission_sets.is_empty()
|
||||
|| !app_acl.manifest.permissions.is_empty();
|
||||
if has_app_manifest {
|
||||
acl_manifests.insert(APP_ACL_KEY.into(), app_acl.manifest);
|
||||
}
|
||||
|
||||
acl_manifests.extend(inline_plugins(out_dir, attributes.inlined_plugins.clone())?);
|
||||
let inline_plugins_acl = inline_plugins(out_dir, attributes.inlined_plugins.clone())?;
|
||||
|
||||
acl_manifests.extend(inline_plugins_acl.manifests);
|
||||
|
||||
let acl_manifests_path = save_acl_manifests(&acl_manifests)?;
|
||||
fs::copy(acl_manifests_path, out_dir.join(ACL_MANIFESTS_FILE_NAME))?;
|
||||
@@ -410,7 +432,12 @@ pub fn build(out_dir: &Path, target: Target, attributes: &Attributes) -> super::
|
||||
let capabilities_path = save_capabilities(&capabilities)?;
|
||||
fs::copy(capabilities_path, out_dir.join(CAPABILITIES_FILE_NAME))?;
|
||||
|
||||
tauri_utils::plugin::save_global_api_scripts_paths(out_dir);
|
||||
let mut permissions_map = inline_plugins_acl.permission_files;
|
||||
if has_app_manifest {
|
||||
permissions_map.insert(APP_ACL_KEY.to_string(), app_acl.permission_files);
|
||||
}
|
||||
|
||||
tauri_utils::acl::build::generate_allowed_commands(out_dir, permissions_map)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -419,23 +419,26 @@ pub fn is_dev() -> bool {
|
||||
|
||||
/// Run all build time helpers for your Tauri Application.
|
||||
///
|
||||
/// The current helpers include the following:
|
||||
/// * Generates a Windows Resource file when targeting Windows.
|
||||
/// To provide extra configuration, such as [`AppManifest::commands`]
|
||||
/// for fine-grained control over command permissions, see [`try_build`].
|
||||
/// See [`Attributes`] for the complete list of configuration options.
|
||||
///
|
||||
/// # Platforms
|
||||
///
|
||||
/// [`build()`] should be called inside of `build.rs` regardless of the platform:
|
||||
/// * New helpers may target more platforms in the future.
|
||||
/// * Platform specific code is handled by the helpers automatically.
|
||||
/// * A build script is required in order to activate some cargo environmental variables that are
|
||||
/// used when generating code and embedding assets - so [`build()`] may as well be called.
|
||||
/// [`build()`] should be called inside of `build.rs` regardless of the platform, so **DO NOT** use a [conditional compilation]
|
||||
/// check that prevents it from running on any of your targets.
|
||||
///
|
||||
/// In short, this is saying don't put the call to [`build()`] behind a `#[cfg(windows)]`.
|
||||
/// Platform specific code is handled by the helpers automatically.
|
||||
///
|
||||
/// A build script is required in order to activate some cargo environmental variables that are
|
||||
/// used when generating code and embedding assets.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If any of the build time helpers fail, they will [`std::panic!`] with the related error message.
|
||||
/// This is typically desirable when running inside a build script; see [`try_build`] for no panics.
|
||||
///
|
||||
/// [conditional compilation]: https://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/html/book/first-edition/conditional-compilation.html
|
||||
pub fn build() {
|
||||
if let Err(error) = try_build(Attributes::default()) {
|
||||
let error = format!("{error:#}");
|
||||
@@ -450,18 +453,12 @@ pub fn build() {
|
||||
}
|
||||
}
|
||||
|
||||
/// Non-panicking [`build()`].
|
||||
/// Same as [`build()`], but takes an extra configuration argument, and does not panic.
|
||||
#[allow(unused_variables)]
|
||||
pub fn try_build(attributes: Attributes) -> Result<()> {
|
||||
use anyhow::anyhow;
|
||||
|
||||
println!("cargo:rerun-if-env-changed=TAURI_CONFIG");
|
||||
#[cfg(feature = "config-json")]
|
||||
println!("cargo:rerun-if-changed=tauri.conf.json");
|
||||
#[cfg(feature = "config-json5")]
|
||||
println!("cargo:rerun-if-changed=tauri.conf.json5");
|
||||
#[cfg(feature = "config-toml")]
|
||||
println!("cargo:rerun-if-changed=Tauri.toml");
|
||||
|
||||
let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap();
|
||||
let mobile = target_os == "ios" || target_os == "android";
|
||||
@@ -471,12 +468,11 @@ pub fn try_build(attributes: Attributes) -> Result<()> {
|
||||
let target_triple = env::var("TARGET").unwrap();
|
||||
let target = tauri_utils::platform::Target::from_triple(&target_triple);
|
||||
|
||||
let (config, merged_config_path) =
|
||||
tauri_utils::config::parse::read_from(target, env::current_dir().unwrap())?;
|
||||
if let Some(merged_config_path) = merged_config_path {
|
||||
println!("cargo:rerun-if-changed={}", merged_config_path.display());
|
||||
let (mut config, config_paths) =
|
||||
tauri_utils::config::parse::read_from(target, &env::current_dir().unwrap())?;
|
||||
for config_file_path in config_paths {
|
||||
println!("cargo:rerun-if-changed={}", config_file_path.display());
|
||||
}
|
||||
let mut config = serde_json::from_value(config)?;
|
||||
if let Ok(env) = env::var("TAURI_CONFIG") {
|
||||
let merge_config: serde_json::Value = serde_json::from_str(&env)?;
|
||||
json_patch::merge(&mut config, &merge_config);
|
||||
@@ -515,6 +511,8 @@ pub fn try_build(attributes: Attributes) -> Result<()> {
|
||||
|
||||
acl::build(&out_dir, target, &attributes)?;
|
||||
|
||||
tauri_utils::plugin::save_global_api_scripts_paths(&out_dir, None);
|
||||
|
||||
println!("cargo:rustc-env=TAURI_ENV_TARGET_TRIPLE={target_triple}");
|
||||
// when running codegen in this build script, we need to access the env var directly
|
||||
env::set_var("TAURI_ENV_TARGET_TRIPLE", &target_triple);
|
||||
@@ -613,7 +611,7 @@ pub fn try_build(attributes: Attributes) -> Result<()> {
|
||||
|
||||
if let Some(version_str) = &config.version {
|
||||
if let Ok(v) = Version::parse(version_str) {
|
||||
let version = v.major << 48 | v.minor << 32 | v.patch << 16;
|
||||
let version = (v.major << 48) | (v.minor << 32) | (v.patch << 16);
|
||||
res.set_version_info(VersionInfo::FILEVERSION, version);
|
||||
res.set_version_info(VersionInfo::PRODUCTVERSION, version);
|
||||
}
|
||||
@@ -623,6 +621,17 @@ pub fn try_build(attributes: Attributes) -> Result<()> {
|
||||
res.set("ProductName", product_name);
|
||||
}
|
||||
|
||||
let company_name = config.bundle.publisher.unwrap_or_else(|| {
|
||||
config
|
||||
.identifier
|
||||
.split('.')
|
||||
.nth(1)
|
||||
.unwrap_or(&config.identifier)
|
||||
.to_string()
|
||||
});
|
||||
|
||||
res.set("CompanyName", &company_name);
|
||||
|
||||
let file_description = config
|
||||
.product_name
|
||||
.or_else(|| manifest.package.as_ref().map(|p| p.name.clone()))
|
||||
|
||||
@@ -1,5 +1,83 @@
|
||||
# Changelog
|
||||
|
||||
## \[2.4.0]
|
||||
|
||||
### New Features
|
||||
|
||||
- [`b0babb6df`](https://www.github.com/tauri-apps/tauri/commit/b0babb6df12dafe45c21a2c9c424fd86ffd75ca7) ([#12938](https://www.github.com/tauri-apps/tauri/pull/12938)) Added hebrew translation for the custom Tauri messages in the NSIS bundle.
|
||||
- [`0aa48fb9e`](https://www.github.com/tauri-apps/tauri/commit/0aa48fb9e4b9d7b5bf3522000a76ebc1836394ed) ([#13030](https://www.github.com/tauri-apps/tauri/pull/13030)) Added `bundleVersion` to iOS and macOS configuration to support specifying a `CFBundleVersion`.
|
||||
|
||||
### Enhancements
|
||||
|
||||
- [`8d994f60f`](https://www.github.com/tauri-apps/tauri/commit/8d994f60fe05ec0f45cbe926506bbe10b0d36e3c) ([#11676](https://www.github.com/tauri-apps/tauri/pull/11676)) Sign NSIS and WiX DLLs when bundling
|
||||
- [`8d994f60f`](https://www.github.com/tauri-apps/tauri/commit/8d994f60fe05ec0f45cbe926506bbe10b0d36e3c) ([#11676](https://www.github.com/tauri-apps/tauri/pull/11676)) Sign DLLs from resources.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- [`9ea76503d`](https://www.github.com/tauri-apps/tauri/commit/9ea76503dcf8da11fab65550f4ab8d3565a424ef) ([#13186](https://www.github.com/tauri-apps/tauri/pull/13186)) Fix NSIS bundler can't include resources and sidecars with `$` in the path
|
||||
- [`2dccfab53`](https://www.github.com/tauri-apps/tauri/commit/2dccfab5321fef55d45f3a4c674b6151b1c4424a) ([#13236](https://www.github.com/tauri-apps/tauri/pull/13236)) Fix `fileAssociations` missing `LSHandlerRank` on macOS.
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `tauri-utils@2.4.0`
|
||||
|
||||
## \[2.3.1]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- [`2138bbc21`](https://www.github.com/tauri-apps/tauri/commit/2138bbc21294785df5f4144670104387289f79c1) ([#13087](https://www.github.com/tauri-apps/tauri/pull/13087) by [@Legend-Master](https://www.github.com/tauri-apps/tauri/../../Legend-Master)) Fix NSIS installer displaying in wrong language if `SpanishInternational` is included
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `tauri-utils@2.3.1`
|
||||
|
||||
## \[2.3.0]
|
||||
|
||||
### Enhancements
|
||||
|
||||
- [`f981a5ee8`](https://www.github.com/tauri-apps/tauri/commit/f981a5ee8b292b9ea09329f60cecc7f688dda734) ([#12602](https://www.github.com/tauri-apps/tauri/pull/12602) by [@kxxt](https://www.github.com/tauri-apps/tauri/../../kxxt)) Add basic support for linux riscv64 platform.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- [`3626b7a92`](https://www.github.com/tauri-apps/tauri/commit/3626b7a92be2890a82e8d5bd00d13887e199ea4a) ([#12759](https://www.github.com/tauri-apps/tauri/pull/12759) by [@ninjadev64](https://www.github.com/tauri-apps/tauri/../../ninjadev64)) Fix resources being bundled to the wrong path during RPM bundling when resources are specified as a map.
|
||||
- [`2b960dfd9`](https://www.github.com/tauri-apps/tauri/commit/2b960dfd9fdc995bd6474958c05783ff53b64b7e) ([#12643](https://www.github.com/tauri-apps/tauri/pull/12643) by [@animeshchaudhri](https://www.github.com/tauri-apps/tauri/../../animeshchaudhri)) Remove the autostart plugin registry entry when the app is uninstalled (NSIS only).
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `tauri-utils@2.3.0`
|
||||
|
||||
## \[2.2.4]
|
||||
|
||||
### Enhancements
|
||||
|
||||
- [`5eba0785c`](https://www.github.com/tauri-apps/tauri/commit/5eba0785c461a0d0bec47653eaf6ccdf5f05d347) ([#12605](https://www.github.com/tauri-apps/tauri/pull/12605) by [@niusia-ua](https://www.github.com/tauri-apps/tauri/../../niusia-ua)) Added Ukrainian translation for the custom tauri messages in the nsis bundle
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `tauri-utils@2.2.0`
|
||||
- Upgraded to `tauri-macos-sign@2.1.0`
|
||||
|
||||
## \[2.2.3]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- [`de8600b4d`](https://www.github.com/tauri-apps/tauri/commit/de8600b4d9a04e809e078c8aea61825d1328201f) ([#12471](https://www.github.com/tauri-apps/tauri/pull/12471) by [@anatawa12](https://www.github.com/tauri-apps/tauri/../../anatawa12)) Bumped `nsis-tauri-utils` to `0.4.2` which fixes the following bugs:
|
||||
|
||||
- Fixed launch on start checkbox in nsis installer does not work well with applications that require elevated permissions
|
||||
- Fixed nsis installer may fail to install if launched by updater plugin
|
||||
- [`fbe7c9ead`](https://www.github.com/tauri-apps/tauri/commit/fbe7c9ead76e71ca258c6f48bbb62185fcc37b1c) ([#12466](https://www.github.com/tauri-apps/tauri/pull/12466) by [@FabianLars](https://www.github.com/tauri-apps/tauri/../../FabianLars)) Fixed an issue that caused the compiled AppImage to miss webkitgtk's internal `libwebkit2gtkinjectedbundle.so` file.
|
||||
- [`f5a59b93b`](https://www.github.com/tauri-apps/tauri/commit/f5a59b93bfefb43ff131a7870b3c5d5e48c1ca1e) ([#12136](https://www.github.com/tauri-apps/tauri/pull/12136) by [@unknovvn](https://www.github.com/tauri-apps/tauri/../../unknovvn)) The NSIS bundler will now replace non-numeric build metadata with `0` instead of returning an error.
|
||||
- [`9dac2863a`](https://www.github.com/tauri-apps/tauri/commit/9dac2863afa70fb0bcddf859b284afba917f28ae) ([#12323](https://www.github.com/tauri-apps/tauri/pull/12323) by [@FabianLars](https://www.github.com/tauri-apps/tauri/../../FabianLars)) Skip signing the .dmg if self signing via `"signingIdentity": "-"` is used.
|
||||
- [`b8eb28877`](https://www.github.com/tauri-apps/tauri/commit/b8eb28877fe822dbe17999fc8af98ed7d0983679) ([#12427](https://www.github.com/tauri-apps/tauri/pull/12427) by [@Legend-Master](https://www.github.com/tauri-apps/tauri/../../Legend-Master)) Clean up `Software\${MANUFACTURER}\${PRODUCTNAME}` registry key in the NSIS uninstaller if "Delete application data" option is checked when uninstalling.
|
||||
|
||||
## \[2.2.2]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- [`72748cc45`](https://www.github.com/tauri-apps/tauri/commit/72748cc45cf670dd03c86c8deceb5942598f5ad9) ([#12365](https://www.github.com/tauri-apps/tauri/pull/12365) by [@don41382](https://www.github.com/tauri-apps/tauri/../../don41382)) Fixed an issue that caused the `.msi` installer not to lookup the `INSTALLDIR` set in the `nsis` installer.
|
||||
- [`cf771bf69`](https://www.github.com/tauri-apps/tauri/commit/cf771bf69aa26b62d11a54a69131c631505d8c55) ([#12402](https://www.github.com/tauri-apps/tauri/pull/12402) by [@FabianLars](https://www.github.com/tauri-apps/tauri/../../FabianLars)) Fixed an issue that caused the .msi installer to not contain root resources when there were .dll files present in the target directory.
|
||||
- [`07ccdc499`](https://www.github.com/tauri-apps/tauri/commit/07ccdc499c3240e7240be3abf95ef2d7d00b2dc7) ([#12324](https://www.github.com/tauri-apps/tauri/pull/12324) by [@FabianLars](https://www.github.com/tauri-apps/tauri/../../FabianLars)) Fixed an issue leading to NSIS based installers to not contain the `WebView2Loader.dll` file when targetting `windows-gnu`.
|
||||
|
||||
## \[2.2.1]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tauri-bundler"
|
||||
version = "2.2.1"
|
||||
version = "2.4.0"
|
||||
authors = [
|
||||
"George Burton <burtonageo@gmail.com>",
|
||||
"Tauri Programme within The Commons Conservancy",
|
||||
@@ -15,7 +15,7 @@ rust-version = "1.77.2"
|
||||
exclude = ["CHANGELOG.md", "/target", "rustfmt.toml"]
|
||||
|
||||
[dependencies]
|
||||
tauri-utils = { version = "2.1.1", path = "../tauri-utils", features = [
|
||||
tauri-utils = { version = "2.4.0", path = "../tauri-utils", features = [
|
||||
"resources",
|
||||
] }
|
||||
image = "0.25"
|
||||
@@ -30,9 +30,9 @@ walkdir = "2"
|
||||
handlebars = "6"
|
||||
tempfile = "3"
|
||||
log = { version = "0.4.21", features = ["kv"] }
|
||||
dirs = "5"
|
||||
dirs = "6"
|
||||
os_pipe = "1"
|
||||
ureq = { version = "2", default-features = false, features = ["socks-proxy"] }
|
||||
ureq = { version = "3", default-features = false, features = ["socks-proxy"] }
|
||||
native-tls = { version = "0.2", optional = true }
|
||||
hex = "0.4"
|
||||
semver = "1"
|
||||
@@ -46,7 +46,7 @@ regex = "1"
|
||||
|
||||
[target."cfg(target_os = \"windows\")".dependencies]
|
||||
bitness = "0.4"
|
||||
windows-registry = "0.4"
|
||||
windows-registry = "0.5"
|
||||
glob = "0.3"
|
||||
|
||||
[target."cfg(target_os = \"windows\")".dependencies.windows-sys]
|
||||
@@ -57,7 +57,7 @@ features = ["Win32_System_SystemInformation", "Win32_System_Diagnostics_Debug"]
|
||||
icns = { package = "tauri-icns", version = "0.1" }
|
||||
time = { version = "0.3", features = ["formatting"] }
|
||||
plist = "1"
|
||||
tauri-macos-sign = { version = "2.0.1", path = "../tauri-macos-sign" }
|
||||
tauri-macos-sign = { version = "2.1.0", path = "../tauri-macos-sign" }
|
||||
|
||||
[target."cfg(target_os = \"linux\")".dependencies]
|
||||
heck = "0.5"
|
||||
@@ -65,6 +65,9 @@ ar = "0.9"
|
||||
md5 = "0.7"
|
||||
rpm = { version = "0.16", features = ["bzip2-compression"] }
|
||||
|
||||
[target."cfg(unix)".dependencies]
|
||||
which = "7"
|
||||
|
||||
[lib]
|
||||
name = "tauri_bundler"
|
||||
path = "src/lib.rs"
|
||||
@@ -73,4 +76,4 @@ path = "src/lib.rs"
|
||||
default = ["rustls"]
|
||||
native-tls = ["ureq/native-tls"]
|
||||
native-tls-vendored = ["native-tls", "native-tls/vendored"]
|
||||
rustls = ["ureq/tls"]
|
||||
rustls = ["ureq/rustls"]
|
||||
|
||||
@@ -19,8 +19,8 @@ pub use self::{
|
||||
category::AppCategory,
|
||||
settings::{
|
||||
AppImageSettings, BundleBinary, BundleSettings, CustomSignCommandSettings, DebianSettings,
|
||||
DmgSettings, MacOsSettings, PackageSettings, PackageType, Position, RpmSettings, Settings,
|
||||
SettingsBuilder, Size, UpdaterSettings,
|
||||
DmgSettings, IosSettings, MacOsSettings, PackageSettings, PackageType, Position, RpmSettings,
|
||||
Settings, SettingsBuilder, Size, UpdaterSettings,
|
||||
},
|
||||
};
|
||||
#[cfg(target_os = "macos")]
|
||||
|
||||
@@ -33,7 +33,12 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<PathBuf>> {
|
||||
}
|
||||
};
|
||||
|
||||
let tools_arch = settings.target().split('-').next().unwrap();
|
||||
let tools_arch = if settings.binary_arch() == Arch::Armhf {
|
||||
"armhf"
|
||||
} else {
|
||||
settings.target().split('-').next().unwrap()
|
||||
};
|
||||
|
||||
let output_path = settings.project_out_directory().join("bundle/appimage");
|
||||
if output_path.exists() {
|
||||
fs::remove_dir_all(&output_path)?;
|
||||
@@ -141,7 +146,7 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<PathBuf>> {
|
||||
for file in [
|
||||
"WebKitNetworkProcess",
|
||||
"WebKitWebProcess",
|
||||
"libwebkit2gtkinjectedbundle.so",
|
||||
"injected-bundle/libwebkit2gtkinjectedbundle.so",
|
||||
] {
|
||||
for source in search_dirs.map(PathBuf::from) {
|
||||
// TODO: Check if it's the same dir name on all systems
|
||||
@@ -181,6 +186,7 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<PathBuf>> {
|
||||
|
||||
let mut cmd = Command::new(linuxdeploy_path);
|
||||
cmd.env("OUTPUT", &appimage_path);
|
||||
cmd.env("ARCH", tools_arch);
|
||||
cmd.args([
|
||||
"--appimage-extract-and-run",
|
||||
"--verbosity",
|
||||
|
||||
@@ -46,6 +46,7 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<PathBuf>> {
|
||||
Arch::AArch64 => "arm64",
|
||||
Arch::Armhf => "armhf",
|
||||
Arch::Armel => "armel",
|
||||
Arch::Riscv64 => "riscv64",
|
||||
target => {
|
||||
return Err(crate::Error::ArchError(format!(
|
||||
"Unsupported architecture: {:?}",
|
||||
|
||||
@@ -29,6 +29,7 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<PathBuf>> {
|
||||
Arch::AArch64 => "aarch64",
|
||||
Arch::Armhf => "armhfp",
|
||||
Arch::Armel => "armel",
|
||||
Arch::Riscv64 => "riscv64",
|
||||
target => {
|
||||
return Err(crate::Error::ArchError(format!(
|
||||
"Unsupported architecture: {:?}",
|
||||
@@ -186,10 +187,10 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<PathBuf>> {
|
||||
FileOptions::new(resource_dir.to_string_lossy()).mode(FileMode::Dir { permissions: 0o755 }),
|
||||
)?;
|
||||
// Then add the resources files in that directory
|
||||
for src in settings.resource_files() {
|
||||
let src = src?;
|
||||
let dest = resource_dir.join(tauri_utils::resources::resource_relpath(&src));
|
||||
builder = builder.with_file(&src, FileOptions::new(dest.to_string_lossy()))?;
|
||||
for resource in settings.resource_files().iter() {
|
||||
let resource = resource?;
|
||||
let dest = resource_dir.join(resource.target());
|
||||
builder = builder.with_file(resource.path(), FileOptions::new(dest.to_string_lossy()))?;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -191,12 +191,6 @@ fn create_info_plist(
|
||||
bundle_icon_file: Option<PathBuf>,
|
||||
settings: &Settings,
|
||||
) -> crate::Result<()> {
|
||||
let format = time::format_description::parse("[year][month][day].[hour][minute][second]")
|
||||
.map_err(time::error::Error::from)?;
|
||||
let build_number = time::OffsetDateTime::now_utc()
|
||||
.format(&format)
|
||||
.map_err(time::error::Error::from)?;
|
||||
|
||||
let mut plist = plist::Dictionary::new();
|
||||
plist.insert("CFBundleDevelopmentRegion".into(), "English".into());
|
||||
plist.insert("CFBundleDisplayName".into(), settings.product_name().into());
|
||||
@@ -226,7 +220,15 @@ fn create_info_plist(
|
||||
"CFBundleShortVersionString".into(),
|
||||
settings.version_string().into(),
|
||||
);
|
||||
plist.insert("CFBundleVersion".into(), build_number.into());
|
||||
plist.insert(
|
||||
"CFBundleVersion".into(),
|
||||
settings
|
||||
.macos()
|
||||
.bundle_version
|
||||
.as_deref()
|
||||
.unwrap_or_else(|| settings.version_string())
|
||||
.into(),
|
||||
);
|
||||
plist.insert("CSResourcesFileMapped".into(), true.into());
|
||||
if let Some(category) = settings.app_category() {
|
||||
plist.insert(
|
||||
@@ -269,6 +271,7 @@ fn create_info_plist(
|
||||
"CFBundleTypeRole".into(),
|
||||
association.role.to_string().into(),
|
||||
);
|
||||
dict.insert("LSHandlerRank".into(), association.rank.to_string().into());
|
||||
plist::Value::Dictionary(dict)
|
||||
})
|
||||
.collect(),
|
||||
|
||||
@@ -194,16 +194,19 @@ pub fn bundle_project(settings: &Settings, bundles: &[Bundle]) -> crate::Result<
|
||||
fs::rename(bundle_dir.join(dmg_name), dmg_path.clone())?;
|
||||
|
||||
// Sign DMG if needed
|
||||
|
||||
if let Some(keychain) = super::sign::keychain(settings.macos().signing_identity.as_deref())? {
|
||||
super::sign::sign(
|
||||
&keychain,
|
||||
vec![super::sign::SignTarget {
|
||||
path: dmg_path.clone(),
|
||||
is_an_executable: false,
|
||||
}],
|
||||
settings,
|
||||
)?;
|
||||
// skipping self-signing DMGs https://github.com/tauri-apps/tauri/issues/12288
|
||||
let identity = settings.macos().signing_identity.as_deref();
|
||||
if identity != Some("-") {
|
||||
if let Some(keychain) = super::sign::keychain(identity)? {
|
||||
super::sign::sign(
|
||||
&keychain,
|
||||
vec![super::sign::SignTarget {
|
||||
path: dmg_path.clone(),
|
||||
is_an_executable: false,
|
||||
}],
|
||||
settings,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Bundled {
|
||||
|
||||
@@ -178,7 +178,11 @@ fn generate_info_plist(
|
||||
writeln!(
|
||||
file,
|
||||
" <key>CFBundleVersion</key>\n <string>{}</string>",
|
||||
settings.version_string()
|
||||
settings
|
||||
.ios()
|
||||
.bundle_version
|
||||
.as_deref()
|
||||
.unwrap_or_else(|| settings.version_string())
|
||||
)?;
|
||||
writeln!(
|
||||
file,
|
||||
|
||||
@@ -48,9 +48,14 @@ pub fn sign(
|
||||
log::info!(action = "Signing"; "with identity \"{}\"", keychain.signing_identity());
|
||||
|
||||
for target in targets {
|
||||
let entitlements_path = if target.is_an_executable {
|
||||
settings.macos().entitlements.as_ref().map(Path::new)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
keychain.sign(
|
||||
&target.path,
|
||||
settings.macos().entitlements.as_ref().map(Path::new),
|
||||
entitlements_path,
|
||||
target.is_an_executable && settings.macos().hardened_runtime,
|
||||
)?;
|
||||
}
|
||||
|
||||
@@ -57,6 +57,8 @@ pub fn target_triple() -> Result<String, crate::Error> {
|
||||
"armv7".into()
|
||||
} else if cfg!(target_arch = "aarch64") {
|
||||
"aarch64".into()
|
||||
} else if cfg!(target_arch = "riscv64") {
|
||||
"riscv64".into()
|
||||
} else {
|
||||
return Err(crate::Error::ArchError(String::from(
|
||||
"Unable to determine target-architecture",
|
||||
|
||||
@@ -306,6 +306,13 @@ pub struct DmgSettings {
|
||||
pub application_folder_position: Position,
|
||||
}
|
||||
|
||||
/// The iOS bundle settings.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct IosSettings {
|
||||
/// The version of the build that identifies an iteration of the bundle.
|
||||
pub bundle_version: Option<String>,
|
||||
}
|
||||
|
||||
/// The macOS bundle settings.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct MacOsSettings {
|
||||
@@ -323,6 +330,8 @@ pub struct MacOsSettings {
|
||||
/// List of custom files to add to the application bundle.
|
||||
/// Maps the path in the Contents directory in the app to the path of the file to include (relative to the current working directory).
|
||||
pub files: HashMap<PathBuf, PathBuf>,
|
||||
/// The version of the build that identifies an iteration of the bundle.
|
||||
pub bundle_version: Option<String>,
|
||||
/// A version string indicating the minimum MacOS version that the bundled app supports (e.g. `"10.11"`).
|
||||
/// If you are using this config field, you may also want have your `build.rs` script emit `cargo:rustc-env=MACOSX_DEPLOYMENT_TARGET=10.11`.
|
||||
pub minimum_system_version: Option<String>,
|
||||
@@ -643,6 +652,8 @@ pub struct BundleSettings {
|
||||
pub rpm: RpmSettings,
|
||||
/// DMG-specific settings.
|
||||
pub dmg: DmgSettings,
|
||||
/// iOS-specific settings.
|
||||
pub ios: IosSettings,
|
||||
/// MacOS-specific settings.
|
||||
pub macos: MacOsSettings,
|
||||
/// Updater configuration.
|
||||
@@ -723,6 +734,8 @@ pub enum Arch {
|
||||
Armhf,
|
||||
/// For the AArch32 / ARM32 instruction sets with soft-float (32 bits).
|
||||
Armel,
|
||||
/// For the RISC-V instruction sets (64 bits).
|
||||
Riscv64,
|
||||
/// For universal macOS applications.
|
||||
Universal,
|
||||
}
|
||||
@@ -900,6 +913,8 @@ impl Settings {
|
||||
Arch::Armel
|
||||
} else if self.target.starts_with("aarch64") {
|
||||
Arch::AArch64
|
||||
} else if self.target.starts_with("riscv64") {
|
||||
Arch::Riscv64
|
||||
} else if self.target.starts_with("universal") {
|
||||
Arch::Universal
|
||||
} else {
|
||||
@@ -1186,6 +1201,11 @@ impl Settings {
|
||||
&self.bundle_settings.dmg
|
||||
}
|
||||
|
||||
/// Returns the iOS settings.
|
||||
pub fn ios(&self) -> &IosSettings {
|
||||
&self.bundle_settings.ios
|
||||
}
|
||||
|
||||
/// Returns the MacOS settings.
|
||||
pub fn macos(&self) -> &MacOsSettings {
|
||||
&self.bundle_settings.macos
|
||||
|
||||
@@ -70,9 +70,12 @@
|
||||
<Property Id="ARPURLUPDATEINFO" Value="{{homepage}}"/>
|
||||
{{/if}}
|
||||
|
||||
<!-- initialize with previous InstallDir -->
|
||||
<Property Id="INSTALLDIR">
|
||||
<RegistrySearch Id="PrevInstallDirReg" Root="HKCU" Key="Software\\{{manufacturer}}\\{{product_name}}" Name="InstallDir" Type="raw"/>
|
||||
<!-- First attempt: Search for "InstallDir" -->
|
||||
<RegistrySearch Id="PrevInstallDirWithName" Root="HKCU" Key="Software\\{{manufacturer}}\\{{product_name}}" Name="InstallDir" Type="raw" />
|
||||
|
||||
<!-- Second attempt: If the first fails, search for the default key value (this is how the nsis installer currently stores the path) -->
|
||||
<RegistrySearch Id="PrevInstallDirNoName" Root="HKCU" Key="Software\\{{manufacturer}}\\{{product_name}}" Type="raw" />
|
||||
</Property>
|
||||
|
||||
<!-- launch app checkbox -->
|
||||
|
||||
@@ -472,6 +472,16 @@ pub fn build_wix_app_installer(
|
||||
}
|
||||
fs::create_dir_all(&output_path)?;
|
||||
|
||||
// when we're performing code signing, we'll sign some WiX DLLs, so we make a local copy
|
||||
let wix_toolset_path = if settings.can_sign() {
|
||||
let wix_path = output_path.join("wix");
|
||||
crate::utils::fs_utils::copy_dir(wix_toolset_path, &wix_path)
|
||||
.context("failed to copy wix directory")?;
|
||||
wix_path
|
||||
} else {
|
||||
wix_toolset_path.to_path_buf()
|
||||
};
|
||||
|
||||
let mut data = BTreeMap::new();
|
||||
|
||||
let silent_webview_install = if let WebviewInstallMode::DownloadBootstrapper { silent }
|
||||
@@ -763,7 +773,11 @@ pub fn build_wix_app_installer(
|
||||
let fragment = fragment_handlebars.render_template(&fragment_content, &data)?;
|
||||
let mut extensions = Vec::new();
|
||||
for cap in extension_regex.captures_iter(&fragment) {
|
||||
extensions.push(wix_toolset_path.join(format!("Wix{}.dll", &cap[1])));
|
||||
let path = wix_toolset_path.join(format!("Wix{}.dll", &cap[1]));
|
||||
if settings.can_sign() {
|
||||
try_sign(&path, settings)?;
|
||||
}
|
||||
extensions.push(path);
|
||||
}
|
||||
candle_inputs.push((fragment_path, extensions));
|
||||
}
|
||||
@@ -773,11 +787,18 @@ pub fn build_wix_app_installer(
|
||||
fragment_extensions.insert(wix_toolset_path.join("WixUIExtension.dll"));
|
||||
fragment_extensions.insert(wix_toolset_path.join("WixUtilExtension.dll"));
|
||||
|
||||
// sign default extensions
|
||||
if settings.can_sign() {
|
||||
for path in &fragment_extensions {
|
||||
try_sign(path, settings)?;
|
||||
}
|
||||
}
|
||||
|
||||
for (path, extensions) in candle_inputs {
|
||||
for ext in &extensions {
|
||||
fragment_extensions.insert(ext.clone());
|
||||
}
|
||||
run_candle(settings, wix_toolset_path, &output_path, path, extensions)?;
|
||||
run_candle(settings, &wix_toolset_path, &output_path, path, extensions)?;
|
||||
}
|
||||
|
||||
let mut output_paths = Vec::new();
|
||||
@@ -853,7 +874,7 @@ pub fn build_wix_app_installer(
|
||||
log::info!(action = "Running"; "light to produce {}", display_path(&msi_path));
|
||||
|
||||
run_light(
|
||||
wix_toolset_path,
|
||||
&wix_toolset_path,
|
||||
&output_path,
|
||||
arguments,
|
||||
&(fragment_extensions.clone().into_iter().collect()),
|
||||
@@ -968,9 +989,12 @@ fn generate_resource_data(settings: &Settings) -> crate::Result<ResourceMap> {
|
||||
if added_resources.contains(&resource_path) {
|
||||
continue;
|
||||
}
|
||||
|
||||
added_resources.push(resource_path.clone());
|
||||
|
||||
if settings.can_sign() {
|
||||
try_sign(&resource_path, settings)?;
|
||||
}
|
||||
|
||||
let resource_entry = ResourceFile {
|
||||
id: format!("I{}", Uuid::new_v4().as_simple()),
|
||||
guid: Uuid::new_v4().to_string(),
|
||||
@@ -1040,6 +1064,7 @@ fn generate_resource_data(settings: &Settings) -> crate::Result<ResourceMap> {
|
||||
|
||||
let mut dlls = Vec::new();
|
||||
|
||||
// TODO: The bundler should not include all DLLs it finds. Instead it should only include WebView2Loader.dll if present and leave the rest to the resources config.
|
||||
let out_dir = settings.project_out_directory();
|
||||
for dll in glob::glob(
|
||||
&PathBuf::from(glob::Pattern::escape(&out_dir.to_string_lossy()))
|
||||
@@ -1054,6 +1079,10 @@ fn generate_resource_data(settings: &Settings) -> crate::Result<ResourceMap> {
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
if !added_resources.iter().any(|r| r.ends_with(&relative_path)) {
|
||||
if settings.can_sign() {
|
||||
try_sign(resource_path, settings)?;
|
||||
}
|
||||
|
||||
dlls.push(ResourceFile {
|
||||
id: format!("I{}", Uuid::new_v4().as_simple()),
|
||||
guid: Uuid::new_v4().to_string(),
|
||||
@@ -1063,15 +1092,15 @@ fn generate_resource_data(settings: &Settings) -> crate::Result<ResourceMap> {
|
||||
}
|
||||
|
||||
if !dlls.is_empty() {
|
||||
resources.insert(
|
||||
"".to_string(),
|
||||
ResourceDirectory {
|
||||
resources
|
||||
.entry("".to_string())
|
||||
.and_modify(|r| r.files.append(&mut dlls))
|
||||
.or_insert(ResourceDirectory {
|
||||
path: "".to_string(),
|
||||
name: "".to_string(),
|
||||
directories: vec![],
|
||||
files: dlls,
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Ok(resources)
|
||||
|
||||
@@ -47,7 +47,7 @@ ${StrLoc}
|
||||
!define COPYRIGHT "{{copyright}}"
|
||||
!define OUTFILE "{{out_file}}"
|
||||
!define ARCH "{{arch}}"
|
||||
!define PLUGINSPATH "{{additional_plugins_path}}"
|
||||
!define ADDITIONALPLUGINSPATH "{{additional_plugins_path}}"
|
||||
!define ALLOWDOWNGRADES "{{allow_downgrades}}"
|
||||
!define DISPLAYLANGUAGESELECTOR "{{display_language_selector}}"
|
||||
!define INSTALLWEBVIEW2MODE "{{install_webview2_mode}}"
|
||||
@@ -56,7 +56,8 @@ ${StrLoc}
|
||||
!define WEBVIEW2INSTALLERPATH "{{webview2_installer_path}}"
|
||||
!define MINIMUMWEBVIEW2VERSION "{{minimum_webview2_version}}"
|
||||
!define UNINSTKEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCTNAME}"
|
||||
!define MANUPRODUCTKEY "Software\${MANUFACTURER}\${PRODUCTNAME}"
|
||||
!define MANUKEY "Software\${MANUFACTURER}"
|
||||
!define MANUPRODUCTKEY "${MANUKEY}\${PRODUCTNAME}"
|
||||
!define UNINSTALLERSIGNCOMMAND "{{uninstaller_sign_cmd}}"
|
||||
!define ESTIMATEDSIZE "{{estimated_size}}"
|
||||
!define STARTMENUFOLDER "{{start_menu_folder}}"
|
||||
@@ -84,10 +85,8 @@ VIAddVersionKey "LegalCopyright" "${COPYRIGHT}"
|
||||
VIAddVersionKey "FileVersion" "${VERSION}"
|
||||
VIAddVersionKey "ProductVersion" "${VERSION}"
|
||||
|
||||
; Plugins path, currently exists for linux only
|
||||
!if "${PLUGINSPATH}" != ""
|
||||
!addplugindir "${PLUGINSPATH}"
|
||||
!endif
|
||||
# additional plugins
|
||||
!addplugindir "${ADDITIONALPLUGINSPATH}"
|
||||
|
||||
; Uninstaller signing command
|
||||
!if "${UNINSTALLERSIGNCOMMAND}" != ""
|
||||
@@ -629,12 +628,12 @@ Section Install
|
||||
CreateDirectory "$INSTDIR\\{{this}}"
|
||||
{{/each}}
|
||||
{{#each resources}}
|
||||
File /a "/oname={{this.[1]}}" "{{@key}}"
|
||||
File /a "/oname={{this.[1]}}" "{{no-escape @key}}"
|
||||
{{/each}}
|
||||
|
||||
; Copy external binaries
|
||||
{{#each binaries}}
|
||||
File /a "/oname={{this}}" "{{@key}}"
|
||||
File /a "/oname={{this}}" "{{no-escape @key}}"
|
||||
{{/each}}
|
||||
|
||||
; Create file associations
|
||||
@@ -834,12 +833,27 @@ Section Uninstall
|
||||
DeleteRegKey HKCU "${UNINSTKEY}"
|
||||
!endif
|
||||
|
||||
DeleteRegValue HKCU "${MANUPRODUCTKEY}" "Installer Language"
|
||||
; Removes the Autostart entry for ${PRODUCTNAME} from the HKCU Run key if it exists.
|
||||
; This ensures the program does not launch automatically after uninstallation if it exists.
|
||||
; If it doesn't exist, it does nothing.
|
||||
; We do this when not updating (to preserve the registry value on updates)
|
||||
${If} $UpdateMode <> 1
|
||||
DeleteRegValue HKCU "Software\Microsoft\Windows\CurrentVersion\Run" "${PRODUCTNAME}"
|
||||
${EndIf}
|
||||
|
||||
; Delete app data if the checkbox is selected
|
||||
; and if not updating
|
||||
${If} $DeleteAppDataCheckboxState = 1
|
||||
${AndIf} $UpdateMode <> 1
|
||||
; Clear the install location $INSTDIR from registry
|
||||
DeleteRegKey SHCTX "${MANUPRODUCTKEY}"
|
||||
DeleteRegKey /ifempty SHCTX "${MANUKEY}"
|
||||
|
||||
; Clear the install language from registry
|
||||
DeleteRegValue HKCU "${MANUPRODUCTKEY}" "Installer Language"
|
||||
DeleteRegKey /ifempty HKCU "${MANUPRODUCTKEY}"
|
||||
DeleteRegKey /ifempty HKCU "${MANUKEY}"
|
||||
|
||||
SetShellVarContext current
|
||||
RmDir /r "$APPDATA\${BUNDLEID}"
|
||||
RmDir /r "$LOCALAPPDATA\${BUNDLEID}"
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
LangString addOrReinstall ${LANG_HEBREW} "הוסף או התקן מחדש"
|
||||
LangString alreadyInstalled ${LANG_HEBREW} "כבר מותקן"
|
||||
LangString alreadyInstalledLong ${LANG_HEBREW} "${PRODUCTNAME} ${VERSION} כבר מותקן. בחר את הפעולה שברצונך לבצע ולחץ על הבא כדי להמשיך."
|
||||
LangString appRunning ${LANG_HEBREW} "${PRODUCTNAME} פועל! נא לסגור אותו ולנסות שוב."
|
||||
LangString appRunningOkKill ${LANG_HEBREW} "${PRODUCTNAME} פועל!$\nלחץ אישור כדי לסגור אותו."
|
||||
LangString chooseMaintenanceOption ${LANG_HEBREW} "בחר את פעולת התחזוקה לביצוע"
|
||||
LangString choowHowToInstall ${LANG_HEBREW} "בחר איך תרצה להתקין את ${PRODUCTNAME}."
|
||||
LangString createDesktop ${LANG_HEBREW} "צור קיצור דרך בשולחן העבודה"
|
||||
LangString dontUninstall ${LANG_HEBREW} "אל תסיר"
|
||||
LangString dontUninstallDowngrade ${LANG_HEBREW} "אל תסיר (התקנת גרסה ישנה ללא הסרת הגרסה הנוכחית מושעית עבור התקנה זו)"
|
||||
LangString failedToKillApp ${LANG_HEBREW} "עצירת ${PRODUCTNAME} נכשלה. נא לסגור את היישום ולנסות שוב."
|
||||
LangString installingWebview2 ${LANG_HEBREW} "מתקין את WebView2..."
|
||||
LangString newerVersionInstalled ${LANG_HEBREW} "גרסה חדשה יותר של ${PRODUCTNAME} כבר מותקנת! לא מומלץ להתקין גרסה ישנה. אם בכל זאת תרצה להתקין את הגרסה הזו, מומלץ קודם להסיר את הגרסה הנוכחית. בחר את הפעולה שברצונך לבצע ולחץ הבא להמשך."
|
||||
LangString older ${LANG_HEBREW} "ישנה"
|
||||
LangString olderOrUnknownVersionInstalled ${LANG_HEBREW} "גרסה $R4 של ${PRODUCTNAME} מותקנת במערכת שלך. מומלץ להסיר את הגרסה הנוכחית לפני ההתקנה. בחר את הפעולה שברצונך לבצע ולחץ הבא להמשך."
|
||||
LangString silentDowngrades ${LANG_HEBREW} "התקנת גרסה ישנה לא נתמכת בהתקנה זו, אין אפשרות להמשיך עם ההתקנה השקטה, נא להמשיך עם ההתקנה בממשק הגרפי.$\n"
|
||||
LangString unableToUninstall ${LANG_HEBREW} "לא ניתן להסיר!"
|
||||
LangString uninstallApp ${LANG_HEBREW} "הסר את ${PRODUCTNAME}"
|
||||
LangString uninstallBeforeInstalling ${LANG_HEBREW} "הסר את הגרסה הנוכחית לפני התקנת גרסה זו"
|
||||
LangString unknown ${LANG_HEBREW} "לא ידועה"
|
||||
LangString webview2AbortError ${LANG_HEBREW} "התקנת WebView2 נכשלה! היישום אינו יכולה לפעול בלי זה. נסה להפעיל את ההתקנה שוב."
|
||||
LangString webview2DownloadError ${LANG_HEBREW} "שגיאה: הורדת WebView2 נכשלה - $0"
|
||||
LangString webview2DownloadSuccess ${LANG_HEBREW} "מאתחל WebView2 הורד בהצלחה"
|
||||
LangString webview2Downloading ${LANG_HEBREW} "מוריד את מאתחל WebView2..."
|
||||
LangString webview2InstallError ${LANG_HEBREW} "שגיאה: התקנת WebView2 נכשלה עם קוד שגיאה $1"
|
||||
LangString webview2InstallSuccess ${LANG_HEBREW} "WebView2 הותקן בהצלחה"
|
||||
LangString deleteAppData ${LANG_HEBREW} "מחק את נתוני היישום"
|
||||
@@ -1,27 +1,27 @@
|
||||
LangString addOrReinstall ${LANG_SPANISH} "Añadir o reinstalar componentes"
|
||||
LangString alreadyInstalled ${LANG_SPANISH} "Ya está instalado"
|
||||
LangString alreadyInstalledLong ${LANG_SPANISH} "${PRODUCTNAME} ${VERSION} ya está instalado. Seleccione la operación que desee realizar y pulse Siguiente para continuar."
|
||||
LangString appRunning ${LANG_SPANISH} "¡${PRODUCTNAME} está abierto! Por favor ciérrelo e intente de nuevo."
|
||||
LangString appRunningOkKill ${LANG_SPANISH} "¡${PRODUCTNAME} está abierto!$\nPulse Aceptar para cerrarlo."
|
||||
LangString chooseMaintenanceOption ${LANG_SPANISH} "Elija la operación de mantenimiento que desee realizar."
|
||||
LangString choowHowToInstall ${LANG_SPANISH} "Elija cómo desea instalar ${PRODUCTNAME}."
|
||||
LangString createDesktop ${LANG_SPANISH} "Crear acceso directo en el escritorio"
|
||||
LangString dontUninstall ${LANG_SPANISH} "No desinstalar"
|
||||
LangString dontUninstallDowngrade ${LANG_SPANISH} "No desinstalar (Disminuir la versión sin desinstalar está deshabilitado para este instalador)"
|
||||
LangString failedToKillApp ${LANG_SPANISH} "No se ha podido cerrar ${PRODUCTNAME}. Por favor ciérrelo e intente de nuevo."
|
||||
LangString installingWebview2 ${LANG_SPANISH} "Instalando WebView2..."
|
||||
LangString newerVersionInstalled ${LANG_SPANISH} "Ya está instalada una versión más reciente de ${PRODUCTNAME}. No se recomienda que instale una versión anterior. Si realmente desea instalar esta versión anterior, es recomendable desinstalar la versión actual antes de continuar. Seleccione la operación que desee realizar y pulse Siguiente para continuar."
|
||||
LangString older ${LANG_SPANISH} "anterior"
|
||||
LangString olderOrUnknownVersionInstalled ${LANG_SPANISH} "Una versión $R4 de ${PRODUCTNAME} está instalada en su sistema. Es recomendable desinstalar la versión actual antes de continuar. Seleccione la operación que desee realizar y pulse Siguiente para continuar."
|
||||
LangString silentDowngrades ${LANG_SPANISH} "Disminuir la versión está deshabilitado para este instalador. No se puede continuar con el instalador silencioso, por favor use el instalador de interfaz gráfica.$\n"
|
||||
LangString unableToUninstall ${LANG_SPANISH} "No se ha podido desinstalar."
|
||||
LangString uninstallApp ${LANG_SPANISH} "Desinstalar ${PRODUCTNAME}"
|
||||
LangString uninstallBeforeInstalling ${LANG_SPANISH} "Desinstalar antes de instalar"
|
||||
LangString unknown ${LANG_SPANISH} "desconocida"
|
||||
LangString webview2AbortError ${LANG_SPANISH} "No se ha podido instalar WebView2. Intente reiniciar el instalador."
|
||||
LangString webview2DownloadError ${LANG_SPANISH} "Error: No se ha podido descargar WebView2 - $0"
|
||||
LangString webview2DownloadSuccess ${LANG_SPANISH} "El bootstrapper de WebView2 fue descargado con éxito."
|
||||
LangString webview2Downloading ${LANG_SPANISH} "Descargando el bootstrapper de WebView2..."
|
||||
LangString webview2InstallError ${LANG_SPANISH} "Error: La instalación de WebView2 falló con el código $1."
|
||||
LangString webview2InstallSuccess ${LANG_SPANISH} "WebView2 fue instalado con éxito."
|
||||
LangString deleteAppData ${LANG_SPANISH} "Eliminar los datos de aplicación"
|
||||
LangString addOrReinstall ${LANG_SPANISHINTERNATIONAL} "Añadir o reinstalar componentes"
|
||||
LangString alreadyInstalled ${LANG_SPANISHINTERNATIONAL} "Ya está instalado"
|
||||
LangString alreadyInstalledLong ${LANG_SPANISHINTERNATIONAL} "${PRODUCTNAME} ${VERSION} ya está instalado. Seleccione la operación que desee realizar y pulse Siguiente para continuar."
|
||||
LangString appRunning ${LANG_SPANISHINTERNATIONAL} "¡${PRODUCTNAME} está abierto! Por favor ciérrelo e intente de nuevo."
|
||||
LangString appRunningOkKill ${LANG_SPANISHINTERNATIONAL} "¡${PRODUCTNAME} está abierto!$\nPulse Aceptar para cerrarlo."
|
||||
LangString chooseMaintenanceOption ${LANG_SPANISHINTERNATIONAL} "Elija la operación de mantenimiento que desee realizar."
|
||||
LangString choowHowToInstall ${LANG_SPANISHINTERNATIONAL} "Elija cómo desea instalar ${PRODUCTNAME}."
|
||||
LangString createDesktop ${LANG_SPANISHINTERNATIONAL} "Crear acceso directo en el escritorio"
|
||||
LangString dontUninstall ${LANG_SPANISHINTERNATIONAL} "No desinstalar"
|
||||
LangString dontUninstallDowngrade ${LANG_SPANISHINTERNATIONAL} "No desinstalar (Disminuir la versión sin desinstalar está deshabilitado para este instalador)"
|
||||
LangString failedToKillApp ${LANG_SPANISHINTERNATIONAL} "No se ha podido cerrar ${PRODUCTNAME}. Por favor ciérrelo e intente de nuevo."
|
||||
LangString installingWebview2 ${LANG_SPANISHINTERNATIONAL} "Instalando WebView2..."
|
||||
LangString newerVersionInstalled ${LANG_SPANISHINTERNATIONAL} "Ya está instalada una versión más reciente de ${PRODUCTNAME}. No se recomienda que instale una versión anterior. Si realmente desea instalar esta versión anterior, es recomendable desinstalar la versión actual antes de continuar. Seleccione la operación que desee realizar y pulse Siguiente para continuar."
|
||||
LangString older ${LANG_SPANISHINTERNATIONAL} "anterior"
|
||||
LangString olderOrUnknownVersionInstalled ${LANG_SPANISHINTERNATIONAL} "Una versión $R4 de ${PRODUCTNAME} está instalada en su sistema. Es recomendable desinstalar la versión actual antes de continuar. Seleccione la operación que desee realizar y pulse Siguiente para continuar."
|
||||
LangString silentDowngrades ${LANG_SPANISHINTERNATIONAL} "Disminuir la versión está deshabilitado para este instalador. No se puede continuar con el instalador silencioso, por favor use el instalador de interfaz gráfica.$\n"
|
||||
LangString unableToUninstall ${LANG_SPANISHINTERNATIONAL} "No se ha podido desinstalar."
|
||||
LangString uninstallApp ${LANG_SPANISHINTERNATIONAL} "Desinstalar ${PRODUCTNAME}"
|
||||
LangString uninstallBeforeInstalling ${LANG_SPANISHINTERNATIONAL} "Desinstalar antes de instalar"
|
||||
LangString unknown ${LANG_SPANISHINTERNATIONAL} "desconocida"
|
||||
LangString webview2AbortError ${LANG_SPANISHINTERNATIONAL} "No se ha podido instalar WebView2. Intente reiniciar el instalador."
|
||||
LangString webview2DownloadError ${LANG_SPANISHINTERNATIONAL} "Error: No se ha podido descargar WebView2 - $0"
|
||||
LangString webview2DownloadSuccess ${LANG_SPANISHINTERNATIONAL} "El bootstrapper de WebView2 fue descargado con éxito."
|
||||
LangString webview2Downloading ${LANG_SPANISHINTERNATIONAL} "Descargando el bootstrapper de WebView2..."
|
||||
LangString webview2InstallError ${LANG_SPANISHINTERNATIONAL} "Error: La instalación de WebView2 falló con el código $1."
|
||||
LangString webview2InstallSuccess ${LANG_SPANISHINTERNATIONAL} "WebView2 fue instalado con éxito."
|
||||
LangString deleteAppData ${LANG_SPANISHINTERNATIONAL} "Eliminar los datos de aplicación"
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
LangString addOrReinstall ${LANG_UKRAINIAN} "Додати/Перевстановити компоненти"
|
||||
LangString alreadyInstalled ${LANG_UKRAINIAN} "Вже встановлено"
|
||||
LangString alreadyInstalledLong ${LANG_UKRAINIAN} "${PRODUCTNAME} ${VERSION} вже встановлено. Виберіть дію, яку ви хочете виконати, і натисніть Далі, щоб продовжити."
|
||||
LangString appRunning ${LANG_UKRAINIAN} "${PRODUCTNAME} запущено! Будь ласка, спочатку закрийте його, а потім спробуйте ще раз."
|
||||
LangString appRunningOkKill ${LANG_UKRAINIAN} "${PRODUCTNAME} запущено!$\nНатисніть ОК, щоб примусово закрити його"
|
||||
LangString chooseMaintenanceOption ${LANG_UKRAINIAN} "Виберіть дію, яку треба виконати."
|
||||
LangString choowHowToInstall ${LANG_UKRAINIAN} "Виберіть, як ви хочете встановити ${PRODUCTNAME}."
|
||||
LangString createDesktop ${LANG_UKRAINIAN} "Створити ярлик на робочому столі"
|
||||
LangString dontUninstall ${LANG_UKRAINIAN} "Не видаляти"
|
||||
LangString dontUninstallDowngrade ${LANG_UKRAINIAN} "Не видаляти (для цього встановлювача вимкнено зниження версії без видалення)"
|
||||
LangString failedToKillApp ${LANG_UKRAINIAN} "Не вдалося примусово закрити ${PRODUCTNAME}. Будь ласка, спочатку закрийте його, а потім спробуйте ще раз"
|
||||
LangString installingWebview2 ${LANG_UKRAINIAN} "Встановлення WebView2..."
|
||||
LangString newerVersionInstalled ${LANG_UKRAINIAN} "Новіша версія ${PRODUCTNAME} вже встановлена! Встановлювати старішу версію не рекомендується. Якщо ви дійсно хочете встановити цю версію, краще спочатку видаліть поточну. Виберіть дію, яку ви хочете виконати, і натисніть Далі, щоб продовжити."
|
||||
LangString older ${LANG_UKRAINIAN} "старішу"
|
||||
LangString olderOrUnknownVersionInstalled ${LANG_UKRAINIAN} "У вашій системі вже встановлено $R4 версію ${PRODUCTNAME}. Рекомендується видалити поточну версію перед встановленням. Виберіть дію, яку ви хочете виконати, і натисніть Далі, щоб продовжити."
|
||||
LangString silentDowngrades ${LANG_UKRAINIAN} "Для цього встановлювача вимкнено зниження версій. Неможливо продовжити роботу з фоновим встановлювачем. Будь ласка, скористайтеся встановлювачем з графічним інтерфейсом.$\n"
|
||||
LangString unableToUninstall ${LANG_UKRAINIAN} "Не вдалося видалити!"
|
||||
LangString uninstallApp ${LANG_UKRAINIAN} "Видалити ${PRODUCTNAME}"
|
||||
LangString uninstallBeforeInstalling ${LANG_UKRAINIAN} "Видалити перед встановленням"
|
||||
LangString unknown ${LANG_UKRAINIAN} "невідому"
|
||||
LangString webview2AbortError ${LANG_UKRAINIAN} "Не вдалося встановити WebView2! Без нього програма не може працювати. Спробуйте перезапустити встановлювач."
|
||||
LangString webview2DownloadError ${LANG_UKRAINIAN} "Помилка: не вдалося завантажити WebView2 - $0"
|
||||
LangString webview2DownloadSuccess ${LANG_UKRAINIAN} "WebView2 успішно завантажено"
|
||||
LangString webview2Downloading ${LANG_UKRAINIAN} "Завантаження WebView2..."
|
||||
LangString webview2InstallError ${LANG_UKRAINIAN} "Помилка: не вдалося встановити WebView2, код виходу - $1"
|
||||
LangString webview2InstallSuccess ${LANG_UKRAINIAN} "WebView2 успішно встановлено "
|
||||
LangString deleteAppData ${LANG_UKRAINIAN} "Видалити дані програми"
|
||||
@@ -39,8 +39,8 @@ const NSIS_URL: &str =
|
||||
#[cfg(target_os = "windows")]
|
||||
const NSIS_SHA1: &str = "057e83c7d82462ec394af76c87d06733605543d4";
|
||||
const NSIS_TAURI_UTILS_URL: &str =
|
||||
"https://github.com/tauri-apps/nsis-tauri-utils/releases/download/nsis_tauri_utils-v0.4.1/nsis_tauri_utils.dll";
|
||||
const NSIS_TAURI_UTILS_SHA1: &str = "F99A50209A345185A84D34D0E5F66D04C75FF52F";
|
||||
"https://github.com/tauri-apps/nsis-tauri-utils/releases/download/nsis_tauri_utils-v0.4.2/nsis_tauri_utils.dll";
|
||||
const NSIS_TAURI_UTILS_SHA1: &str = "6532DA4545864C6EC95F62F27F2199BFD668560B";
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
const NSIS_REQUIRED_FILES: &[&str] = &[
|
||||
@@ -55,11 +55,18 @@ const NSIS_REQUIRED_FILES: &[&str] = &[
|
||||
"Include/nsDialogs.nsh",
|
||||
"Include/WinMessages.nsh",
|
||||
];
|
||||
const NSIS_PLUGIN_FILES: &[&str] = &[
|
||||
"NSISdl.dll",
|
||||
"StartMenu.dll",
|
||||
"System.dll",
|
||||
"nsDialogs.dll",
|
||||
"additional/nsis_tauri_utils.dll",
|
||||
];
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
const NSIS_REQUIRED_FILES: &[&str] = &["Plugins/x86-unicode/nsis_tauri_utils.dll"];
|
||||
const NSIS_REQUIRED_FILES: &[&str] = &["Plugins/x86-unicode/additional/nsis_tauri_utils.dll"];
|
||||
|
||||
const NSIS_REQUIRED_FILES_HASH: &[(&str, &str, &str, HashAlgorithm)] = &[(
|
||||
"Plugins/x86-unicode/nsis_tauri_utils.dll",
|
||||
"Plugins/x86-unicode/additional/nsis_tauri_utils.dll",
|
||||
NSIS_TAURI_UTILS_URL,
|
||||
NSIS_TAURI_UTILS_SHA1,
|
||||
HashAlgorithm::Sha1,
|
||||
@@ -96,7 +103,10 @@ pub fn bundle_project(settings: &Settings, updater: bool) -> crate::Result<Vec<P
|
||||
log::warn!("NSIS directory contains mis-hashed files. Redownloading them.");
|
||||
for (path, url, hash, hash_algorithm) in mismatched {
|
||||
let data = download_and_verify(url, hash, *hash_algorithm)?;
|
||||
fs::write(nsis_toolset_path.join(path), data)?;
|
||||
let out_path = nsis_toolset_path.join(path);
|
||||
std::fs::create_dir_all(out_path.parent().context("output path has no parent")?)
|
||||
.context("failed to create file output directory")?;
|
||||
fs::write(out_path, data).with_context(|| format!("failed to save {path}"))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -116,6 +126,7 @@ fn get_and_extract_nsis(nsis_toolset_path: &Path, _tauri_tools_path: &Path) -> c
|
||||
fs::rename(_tauri_tools_path.join("nsis-3.08"), nsis_toolset_path)?;
|
||||
}
|
||||
|
||||
// download additional plugins
|
||||
let nsis_plugins = nsis_toolset_path.join("Plugins");
|
||||
|
||||
let data = download_and_verify(
|
||||
@@ -124,14 +135,14 @@ fn get_and_extract_nsis(nsis_toolset_path: &Path, _tauri_tools_path: &Path) -> c
|
||||
HashAlgorithm::Sha1,
|
||||
)?;
|
||||
|
||||
let target_folder = nsis_plugins.join("x86-unicode");
|
||||
let target_folder = nsis_plugins.join("x86-unicode").join("additional");
|
||||
fs::create_dir_all(&target_folder)?;
|
||||
fs::write(target_folder.join("nsis_tauri_utils.dll"), data)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn add_build_number_if_needed(version_str: &str) -> anyhow::Result<String> {
|
||||
fn try_add_numeric_build_number(version_str: &str) -> anyhow::Result<String> {
|
||||
let version = semver::Version::parse(version_str).context("invalid app version")?;
|
||||
if !version.build.is_empty() {
|
||||
let build = version.build.parse::<u64>();
|
||||
@@ -141,7 +152,10 @@ fn add_build_number_if_needed(version_str: &str) -> anyhow::Result<String> {
|
||||
version.major, version.minor, version.patch, version.build
|
||||
));
|
||||
} else {
|
||||
anyhow::bail!("optional build metadata in app version must be numeric-only");
|
||||
log::warn!(
|
||||
"Unable to parse version build metadata. Numeric value expected, received: `{}`. This will be replaced with `0` in `VIProductVersion` because Windows requires this field to be numeric.",
|
||||
version.build
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,9 +164,10 @@ fn add_build_number_if_needed(version_str: &str) -> anyhow::Result<String> {
|
||||
version.major, version.minor, version.patch,
|
||||
))
|
||||
}
|
||||
|
||||
fn build_nsis_app_installer(
|
||||
settings: &Settings,
|
||||
_nsis_toolset_path: &Path,
|
||||
#[allow(unused_variables)] nsis_toolset_path: &Path,
|
||||
tauri_tools_path: &Path,
|
||||
updater: bool,
|
||||
) -> crate::Result<Vec<PathBuf>> {
|
||||
@@ -176,6 +191,65 @@ fn build_nsis_app_installer(
|
||||
}
|
||||
fs::create_dir_all(&output_path)?;
|
||||
|
||||
// we make a copy of the NSIS directory if we're going to sign its DLLs
|
||||
// because we don't want to change the DLL hashes so the cache can reuse it
|
||||
let maybe_plugin_copy_path = if settings.can_sign() {
|
||||
// find nsis path
|
||||
#[cfg(target_os = "linux")]
|
||||
let system_nsis_toolset_path = std::env::var_os("NSIS_PATH")
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|| PathBuf::from("/usr/share/nsis"));
|
||||
#[cfg(target_os = "macos")]
|
||||
let system_nsis_toolset_path = std::env::var_os("NSIS_PATH")
|
||||
.map(PathBuf::from)
|
||||
.ok_or_else(|| anyhow::anyhow!("failed to resolve NSIS path"))
|
||||
.or_else(|_| {
|
||||
let mut makensis_path =
|
||||
which::which("makensis").context("failed to resolve `makensis`; did you install nsis? See https://tauri.app/distribute/windows-installer/#install-nsis for more information")?;
|
||||
// homebrew installs it as a symlink
|
||||
if makensis_path.is_symlink() {
|
||||
// read_link might return a path relative to makensis_path so we must use join() and canonicalize
|
||||
makensis_path = makensis_path
|
||||
.parent()
|
||||
.context("missing makensis parent")?
|
||||
.join(std::fs::read_link(&makensis_path).context("failed to resolve makensis symlink")?)
|
||||
.canonicalize()
|
||||
.context("failed to resolve makensis path")?;
|
||||
}
|
||||
// file structure:
|
||||
// ├── bin
|
||||
// │ ├── makensis
|
||||
// ├── share
|
||||
// │ ├── nsis
|
||||
let bin_folder = makensis_path.parent().context("missing makensis parent")?;
|
||||
let root_folder = bin_folder.parent().context("missing makensis root")?;
|
||||
crate::Result::Ok(root_folder.join("share").join("nsis"))
|
||||
})?;
|
||||
#[cfg(windows)]
|
||||
let system_nsis_toolset_path = nsis_toolset_path.to_path_buf();
|
||||
|
||||
let plugins_path = output_path.join("Plugins");
|
||||
// copy system plugins (we don't want to modify system installed DLLs, and on some systems there will even be permission errors if we try)
|
||||
crate::utils::fs_utils::copy_dir(
|
||||
&system_nsis_toolset_path.join("Plugins").join("x86-unicode"),
|
||||
&plugins_path.join("x86-unicode"),
|
||||
)
|
||||
.context("failed to copy system NSIS Plugins folder to local copy")?;
|
||||
// copy our downloaded DLLs
|
||||
crate::utils::fs_utils::copy_dir(
|
||||
&nsis_toolset_path
|
||||
.join("Plugins")
|
||||
.join("x86-unicode")
|
||||
.join("additional"),
|
||||
&plugins_path.join("x86-unicode").join("additional"),
|
||||
)
|
||||
.context("failed to copy additional NSIS Plugins folder to local copy")?;
|
||||
Some(plugins_path)
|
||||
} else {
|
||||
// in this case plugin_copy_path can be None, we'll use the system default path
|
||||
None
|
||||
};
|
||||
|
||||
let mut data = BTreeMap::new();
|
||||
|
||||
let bundle_id = settings.bundle_identifier();
|
||||
@@ -183,12 +257,17 @@ fn build_nsis_app_installer(
|
||||
.publisher()
|
||||
.unwrap_or_else(|| bundle_id.split('.').nth(1).unwrap_or(bundle_id));
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
let mut dir = dirs::cache_dir().unwrap();
|
||||
dir.extend(["tauri", "NSIS", "Plugins", "x86-unicode"]);
|
||||
data.insert("additional_plugins_path", to_json(dir));
|
||||
}
|
||||
let additional_plugins_path = maybe_plugin_copy_path
|
||||
.clone()
|
||||
.unwrap_or_else(|| nsis_toolset_path.join("Plugins"))
|
||||
.join("x86-unicode")
|
||||
.join("additional");
|
||||
|
||||
data.insert(
|
||||
"additional_plugins_path",
|
||||
// either our Plugins copy (when signing) or the cache/Plugins/x86-unicode path
|
||||
to_json(&additional_plugins_path),
|
||||
);
|
||||
|
||||
data.insert("arch", to_json(arch));
|
||||
data.insert("bundle_id", to_json(bundle_id));
|
||||
@@ -214,7 +293,7 @@ fn build_nsis_app_installer(
|
||||
data.insert("version", to_json(version));
|
||||
data.insert(
|
||||
"version_with_build",
|
||||
to_json(add_build_number_if_needed(version)?),
|
||||
to_json(try_add_numeric_build_number(version)?),
|
||||
);
|
||||
|
||||
data.insert(
|
||||
@@ -463,6 +542,7 @@ fn build_nsis_app_installer(
|
||||
let mut handlebars = Handlebars::new();
|
||||
handlebars.register_helper("or", Box::new(handlebars_or));
|
||||
handlebars.register_helper("association-description", Box::new(association_description));
|
||||
handlebars.register_helper("no-escape", Box::new(handlebars_no_escape));
|
||||
handlebars.register_escape_fn(|s| {
|
||||
let mut output = String::new();
|
||||
for c in s.chars() {
|
||||
@@ -521,13 +601,29 @@ fn build_nsis_app_installer(
|
||||
));
|
||||
fs::create_dir_all(nsis_installer_path.parent().unwrap())?;
|
||||
|
||||
log::info!(action = "Running"; "makensis.exe to produce {}", display_path(&nsis_installer_path));
|
||||
if settings.can_sign() {
|
||||
log::info!("Signing NSIS plugins");
|
||||
for dll in NSIS_PLUGIN_FILES {
|
||||
let path = additional_plugins_path.join(dll);
|
||||
if path.exists() {
|
||||
try_sign(&path, settings)?;
|
||||
} else {
|
||||
log::warn!("Could not find {}, skipping signing", path.display());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log::info!(action = "Running"; "makensis to produce {}", display_path(&nsis_installer_path));
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
let mut nsis_cmd = Command::new(_nsis_toolset_path.join("makensis.exe"));
|
||||
let mut nsis_cmd = Command::new(nsis_toolset_path.join("makensis.exe"));
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let mut nsis_cmd = Command::new("makensis");
|
||||
|
||||
if let Some(plugins_path) = &maybe_plugin_copy_path {
|
||||
nsis_cmd.env("NSISPLUGINS", plugins_path);
|
||||
}
|
||||
|
||||
nsis_cmd
|
||||
.args(["-INPUTCHARSET", "UTF8", "-OUTPUTCHARSET", "UTF8"])
|
||||
.arg(match settings.log_level() {
|
||||
@@ -591,14 +687,49 @@ fn association_description(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handlebars_no_escape(
|
||||
h: &handlebars::Helper<'_>,
|
||||
_: &Handlebars<'_>,
|
||||
_: &handlebars::Context,
|
||||
_: &mut handlebars::RenderContext<'_, '_>,
|
||||
out: &mut dyn handlebars::Output,
|
||||
) -> handlebars::HelperResult {
|
||||
// get parameter from helper or throw an error
|
||||
let param = h
|
||||
.param(0)
|
||||
.ok_or(handlebars::RenderErrorReason::ParamNotFoundForIndex(
|
||||
"no-escape",
|
||||
0,
|
||||
))?;
|
||||
write!(out, "{}", param.render())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// BTreeMap<OriginalPath, (ParentOfTargetPath, TargetPath)>
|
||||
type ResourcesMap = BTreeMap<PathBuf, (PathBuf, PathBuf)>;
|
||||
fn generate_resource_data(settings: &Settings) -> crate::Result<ResourcesMap> {
|
||||
let mut resources = ResourcesMap::new();
|
||||
|
||||
let cwd = std::env::current_dir()?;
|
||||
|
||||
let mut added_resources = Vec::new();
|
||||
|
||||
// Adding WebViewer2Loader.dll in case windows-gnu toolchain is used
|
||||
if settings.target().ends_with("-gnu") {
|
||||
let loader_path =
|
||||
dunce::simplified(&settings.project_out_directory().join("WebView2Loader.dll")).to_path_buf();
|
||||
if loader_path.exists() {
|
||||
if settings.can_sign() {
|
||||
try_sign(&loader_path, settings)?;
|
||||
}
|
||||
added_resources.push(loader_path.clone());
|
||||
resources.insert(
|
||||
loader_path,
|
||||
(PathBuf::new(), PathBuf::from("WebView2Loader.dll")),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for resource in settings.resource_files().iter() {
|
||||
let resource = resource?;
|
||||
|
||||
@@ -613,6 +744,10 @@ fn generate_resource_data(settings: &Settings) -> crate::Result<ResourcesMap> {
|
||||
}
|
||||
added_resources.push(resource_path.clone());
|
||||
|
||||
if settings.can_sign() {
|
||||
try_sign(&resource_path, settings)?;
|
||||
}
|
||||
|
||||
let target_path = resource.target();
|
||||
resources.insert(
|
||||
resource_path,
|
||||
@@ -702,6 +837,7 @@ fn get_lang_data(lang: &str) -> Option<(String, &[u8])> {
|
||||
"turkish" => include_bytes!("./languages/Turkish.nsh"),
|
||||
"swedish" => include_bytes!("./languages/Swedish.nsh"),
|
||||
"portuguese" => include_bytes!("./languages/Portuguese.nsh"),
|
||||
"ukrainian" => include_bytes!("./languages/Ukrainian.nsh"),
|
||||
_ => return None,
|
||||
};
|
||||
Some((path, content))
|
||||
|
||||
@@ -142,12 +142,21 @@ pub fn sign_command_custom<P: AsRef<Path>>(
|
||||
) -> crate::Result<Command> {
|
||||
let path = path.as_ref();
|
||||
|
||||
let cwd = std::env::current_dir()?;
|
||||
|
||||
let mut cmd = Command::new(&command.cmd);
|
||||
for arg in &command.args {
|
||||
if arg == "%1" {
|
||||
cmd.arg(path);
|
||||
} else {
|
||||
cmd.arg(arg);
|
||||
let path = Path::new(arg);
|
||||
// turn relative paths into absolute paths - so the uninstall command can use them
|
||||
// since the !uninstfinalize NSIS hook runs in a different directory
|
||||
if path.exists() && path.is_relative() {
|
||||
cmd.arg(cwd.join(path));
|
||||
} else {
|
||||
cmd.arg(arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(cmd)
|
||||
@@ -241,9 +250,9 @@ pub fn sign<P: AsRef<Path>>(path: P, params: &SignParams) -> crate::Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_sign(file_path: &std::path::PathBuf, settings: &Settings) -> crate::Result<()> {
|
||||
pub fn try_sign<P: AsRef<Path>>(file_path: P, settings: &Settings) -> crate::Result<()> {
|
||||
if settings.can_sign() {
|
||||
log::info!(action = "Signing"; "{}", tauri_utils::display_path(file_path));
|
||||
log::info!(action = "Signing"; "{}", tauri_utils::display_path(file_path.as_ref()));
|
||||
sign(file_path, &settings.sign_params())?;
|
||||
}
|
||||
Ok(())
|
||||
|
||||
@@ -7,6 +7,8 @@ use std::{
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use ureq::ResponseExt;
|
||||
|
||||
use crate::utils::http_utils::download;
|
||||
|
||||
pub const WEBVIEW2_BOOTSTRAPPER_URL: &str = "https://go.microsoft.com/fwlink/p/?LinkId=2124703";
|
||||
@@ -22,9 +24,12 @@ pub const WIX_OUTPUT_FOLDER_NAME: &str = "msi";
|
||||
pub const WIX_UPDATER_OUTPUT_FOLDER_NAME: &str = "msi-updater";
|
||||
|
||||
pub fn webview2_guid_path(url: &str) -> crate::Result<(String, String)> {
|
||||
let agent = ureq::AgentBuilder::new().try_proxy_from_env(true).build();
|
||||
let agent: ureq::Agent = ureq::Agent::config_builder()
|
||||
.proxy(ureq::Proxy::try_from_env())
|
||||
.build()
|
||||
.into();
|
||||
let response = agent.head(url).call().map_err(Box::new)?;
|
||||
let final_url = response.get_url();
|
||||
let final_url = response.get_uri().to_string();
|
||||
let remaining_url = final_url.strip_prefix(WEBVIEW2_URL_PREFIX).ok_or_else(|| {
|
||||
anyhow::anyhow!(
|
||||
"WebView2 URL prefix mismatch. Expected `{}`, found `{}`.",
|
||||
|
||||
@@ -111,9 +111,6 @@ pub fn copy_dir(from: &Path, to: &Path) -> crate::Result<()> {
|
||||
"{from:?} is not a Directory"
|
||||
)));
|
||||
}
|
||||
if to.exists() {
|
||||
return Err(crate::Error::GenericError(format!("{to:?} already exists")));
|
||||
}
|
||||
let parent = to.parent().expect("No data in parent");
|
||||
fs::create_dir_all(parent)?;
|
||||
for entry in walkdir::WalkDir::new(from) {
|
||||
@@ -129,7 +126,7 @@ pub fn copy_dir(from: &Path, to: &Path) -> crate::Result<()> {
|
||||
symlink_file(&target, &dest_path)?;
|
||||
}
|
||||
} else if entry.file_type().is_dir() {
|
||||
fs::create_dir(dest_path)?;
|
||||
fs::create_dir_all(dest_path)?;
|
||||
} else {
|
||||
fs::copy(entry.path(), dest_path)?;
|
||||
}
|
||||
|
||||
@@ -47,12 +47,15 @@ fn generate_github_alternative_url(url: &str) -> Option<(ureq::Agent, String)> {
|
||||
|
||||
generate_github_mirror_url_from_template(url)
|
||||
.or_else(|| generate_github_mirror_url_from_base(url))
|
||||
.map(|alt_url| (ureq::AgentBuilder::new().build(), alt_url))
|
||||
.map(|alt_url| (ureq::agent(), alt_url))
|
||||
}
|
||||
|
||||
fn create_agent_and_url(url: &str) -> (ureq::Agent, String) {
|
||||
generate_github_alternative_url(url).unwrap_or((
|
||||
ureq::AgentBuilder::new().try_proxy_from_env(true).build(),
|
||||
ureq::Agent::config_builder()
|
||||
.proxy(ureq::Proxy::try_from_env())
|
||||
.build()
|
||||
.into(),
|
||||
url.to_owned(),
|
||||
))
|
||||
}
|
||||
@@ -65,7 +68,7 @@ pub fn download(url: &str) -> crate::Result<Vec<u8>> {
|
||||
|
||||
let response = agent.get(&final_url).call().map_err(Box::new)?;
|
||||
let mut bytes = Vec::new();
|
||||
response.into_reader().read_to_end(&mut bytes)?;
|
||||
response.into_body().into_reader().read_to_end(&mut bytes)?;
|
||||
Ok(bytes)
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ impl CommandExt for Command {
|
||||
let program = self.get_program().to_string_lossy().into_owned();
|
||||
log::debug!(action = "Running"; "Command `{} {}`", program, self.get_args().map(|arg| arg.to_string_lossy()).fold(String::new(), |acc, arg| format!("{acc} {arg}")));
|
||||
|
||||
self.status().map_err(Into::into)
|
||||
self.status()
|
||||
}
|
||||
|
||||
fn output_ok(&mut self) -> crate::Result<Output> {
|
||||
|
||||
@@ -1,5 +1,115 @@
|
||||
# Changelog
|
||||
|
||||
## \[2.5.0]
|
||||
|
||||
### New Features
|
||||
|
||||
- [`0aa48fb9e`](https://www.github.com/tauri-apps/tauri/commit/0aa48fb9e4b9d7b5bf3522000a76ebc1836394ed) ([#13030](https://www.github.com/tauri-apps/tauri/pull/13030)) Added `bundleVersion` to iOS and macOS configuration to support specifying a `CFBundleVersion`.
|
||||
|
||||
### Enhancements
|
||||
|
||||
- [`ad3fd3890`](https://www.github.com/tauri-apps/tauri/commit/ad3fd3890f1fa26a9f9be04ff1bc156d6dd2a8bc) ([#13152](https://www.github.com/tauri-apps/tauri/pull/13152)) Detect package manager from environment variable `npm_config_user_agent` first
|
||||
- [`82406c61e`](https://www.github.com/tauri-apps/tauri/commit/82406c61e0fbb775ef00791ccab45349325bdd45) ([#13231](https://www.github.com/tauri-apps/tauri/pull/13231)) Improve iOS simulator usage, checking if Xcode iOS SDK is installed and allowing usage of Simulator for older iOS releases (previously only supported when running on Xcode via `ios dev --open`).
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- [`2dccfab53`](https://www.github.com/tauri-apps/tauri/commit/2dccfab5321fef55d45f3a4c674b6151b1c4424a) ([#13236](https://www.github.com/tauri-apps/tauri/pull/13236)) Fix `fileAssociations` missing `LSHandlerRank` on macOS.
|
||||
- [`080252903`](https://www.github.com/tauri-apps/tauri/commit/0802529031c4fd309edff374a8694e93ddec161d) ([#13210](https://www.github.com/tauri-apps/tauri/pull/13210)) Fixes iOS dev not working on Xcode 16.3 simulators. To apply the fix, either regenerate the Xcode project with `rm -r src-tauri/gen/apple && tauri ios init` or remove the `arm64-sim` architecture from the Xcode project.
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `tauri-utils@2.4.0`
|
||||
- Upgraded to `tauri-bundler@2.4.0`
|
||||
|
||||
## \[2.4.1]
|
||||
|
||||
### Enhancements
|
||||
|
||||
- [`f805061d1`](https://www.github.com/tauri-apps/tauri/commit/f805061d1152bc4790dbdb9475a506afcdd1de75) ([#13079](https://www.github.com/tauri-apps/tauri/pull/13079) by [@Pietagorh](https://www.github.com/tauri-apps/tauri/../../Pietagorh)) Add support for passing TOML and JSON5 config files to `--config` arg
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- [`30beb6fee`](https://www.github.com/tauri-apps/tauri/commit/30beb6fee7b052e588ee72c238e315a557b5d6f2) ([#13096](https://www.github.com/tauri-apps/tauri/pull/13096) by [@Legend-Master](https://www.github.com/tauri-apps/tauri/../../Legend-Master)) Fix `tauri info` can't find the latest version for rust crates
|
||||
- [`30beb6fee`](https://www.github.com/tauri-apps/tauri/commit/30beb6fee7b052e588ee72c238e315a557b5d6f2) ([#13096](https://www.github.com/tauri-apps/tauri/pull/13096) by [@Legend-Master](https://www.github.com/tauri-apps/tauri/../../Legend-Master)) Fix `tauri info` logging network operations in `info` level instead of `debug`
|
||||
- [`794af778e`](https://www.github.com/tauri-apps/tauri/commit/794af778e4915ffb6a4fe9bae8fba04bc880503d) ([#13117](https://www.github.com/tauri-apps/tauri/pull/13117) by [@Legend-Master](https://www.github.com/tauri-apps/tauri/../../Legend-Master)) Fix setting merge config value to null with `--config` arg no longer works
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `tauri-bundler@2.3.1`
|
||||
- Upgraded to `tauri-utils@2.3.1`
|
||||
|
||||
## \[2.4.0]
|
||||
|
||||
### New Features
|
||||
|
||||
- [`d91bfa5cb`](https://www.github.com/tauri-apps/tauri/commit/d91bfa5cb921a078758edd45ef3eaff71358d1eb) ([#12970](https://www.github.com/tauri-apps/tauri/pull/12970) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) Allow merging multiple configuration values on `tauri dev`, `tauri build`, `tauri bundle`, `tauri android dev`, `tauri android build`, `tauri ios dev` and `tauri ios build`.
|
||||
- [`013f8f652`](https://www.github.com/tauri-apps/tauri/commit/013f8f652302f2d49c5ec0a075582033d8b074fb) ([#12890](https://www.github.com/tauri-apps/tauri/pull/12890) by [@Legend-Master](https://www.github.com/tauri-apps/tauri/../../Legend-Master)) Reads `build > removeUnusedCommands` from the config file and pass in the environment variables on the build command to trigger the build scripts and macros to remove unused commands based on the capabilities you defined. For this to work on inlined plugins you must add a `#![plugin(<insert_plugin_name>)]` inside the `tauri::generate_handler![]` usage and the app manifest must be set.
|
||||
- [`30f5a1553`](https://www.github.com/tauri-apps/tauri/commit/30f5a1553d3c0ce460c9006764200a9210915a44) ([#12366](https://www.github.com/tauri-apps/tauri/pull/12366) by [@FabianLars](https://www.github.com/tauri-apps/tauri/../../FabianLars)) Added `trafficLightPosition` window configuration to set the traffic light buttons position on macOS.
|
||||
|
||||
### Enhancements
|
||||
|
||||
- [`f981a5ee8`](https://www.github.com/tauri-apps/tauri/commit/f981a5ee8b292b9ea09329f60cecc7f688dda734) ([#12602](https://www.github.com/tauri-apps/tauri/pull/12602) by [@kxxt](https://www.github.com/tauri-apps/tauri/../../kxxt)) Add basic support for linux riscv64 platform.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- [`0c4700e99`](https://www.github.com/tauri-apps/tauri/commit/0c4700e9907f242eabe579eb6149a1d75174185c) ([#12985](https://www.github.com/tauri-apps/tauri/pull/12985) by [@FabianLars](https://www.github.com/tauri-apps/tauri/../../FabianLars)) The cli will now accept `--bundles updater` again. It's still no-op as it has been for all v2 versions. If you want to build updater artifacts, enable `createUpdaterArtifacts` in `tauri.conf.json`.
|
||||
- [`eec08a18b`](https://www.github.com/tauri-apps/tauri/commit/eec08a18b66525f5544cd30144d0553260ee3a70) ([#12998](https://www.github.com/tauri-apps/tauri/pull/12998) by [@jason89521](https://www.github.com/tauri-apps/tauri/../../jason89521)) For bun's lockfile, check both `bun.lock` and `bun.lockb`.
|
||||
- [`b83921226`](https://www.github.com/tauri-apps/tauri/commit/b83921226cb3084992bb5357e7e39a09ea97843e) ([#12977](https://www.github.com/tauri-apps/tauri/pull/12977) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) Fix `tauri ios` commands using the wrong working directory with `bun@>1.2`.
|
||||
- [`f268b3dbd`](https://www.github.com/tauri-apps/tauri/commit/f268b3dbdf313484c85b4a1f69cd7cec63049f35) ([#12871](https://www.github.com/tauri-apps/tauri/pull/12871) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) Ignore parent .gitignore files on the Tauri project path detection.
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `tauri-utils@2.3.0`
|
||||
- Upgraded to `tauri-bundler@2.3.0`
|
||||
|
||||
## \[2.3.1]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- [`22e9bf74a`](https://www.github.com/tauri-apps/tauri/commit/22e9bf74a4684c827279a85bb66548e83c1ea5cf) ([#12538](https://www.github.com/tauri-apps/tauri/pull/12538) by [@DeTeam](https://www.github.com/tauri-apps/tauri/../../DeTeam)) Set initialViewController for LaunchScreen (iOS).
|
||||
|
||||
## \[2.3.0]
|
||||
|
||||
### Enhancements
|
||||
|
||||
- [`a2d36b8c3`](https://www.github.com/tauri-apps/tauri/commit/a2d36b8c34a8dcfc6736797ca5cd4665faf75e7e) ([#12181](https://www.github.com/tauri-apps/tauri/pull/12181) by [@bastiankistner](https://www.github.com/tauri-apps/tauri/../../bastiankistner)) Add an option to change the default background throttling policy (currently for WebKit only).
|
||||
- [`6e417c943`](https://www.github.com/tauri-apps/tauri/commit/6e417c9435d8fae0eca9e8d42d6215e887a28d98) ([#12786](https://www.github.com/tauri-apps/tauri/pull/12786) by [@kandrelczyk](https://www.github.com/tauri-apps/tauri/../../kandrelczyk)) Added RPM to the list of package types for which signature file will be generated.
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `tauri-utils@2.2.0`
|
||||
- Upgraded to `tauri-bundler@2.2.4`
|
||||
- Upgraded to `tauri-macos-sign@2.1.0`
|
||||
|
||||
## \[2.2.7]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- [`8e9134c4a`](https://www.github.com/tauri-apps/tauri/commit/8e9134c4a2047329be0dbb868b7ae061a9d3f190) ([#12511](https://www.github.com/tauri-apps/tauri/pull/12511) by [@FabianLars](https://www.github.com/tauri-apps/tauri/../../FabianLars)) Fixed an issue that caused `tauri dev` to fail because of an incorrect `--bins` flag.
|
||||
|
||||
## \[2.2.6]
|
||||
|
||||
### Enhancements
|
||||
|
||||
- [`1a86974aa`](https://www.github.com/tauri-apps/tauri/commit/1a86974aa3d09957c6b1142a17bbfed9998798fd) ([#12406](https://www.github.com/tauri-apps/tauri/pull/12406) by [@bradleat](https://www.github.com/tauri-apps/tauri/../../bradleat)) `ios build --open` will now let xcode start the rust build process.
|
||||
- [`9a30bed98`](https://www.github.com/tauri-apps/tauri/commit/9a30bed98c2d8501328006fad5840eb9d533e1c2) ([#12423](https://www.github.com/tauri-apps/tauri/pull/12423) by [@tr3ysmith](https://www.github.com/tauri-apps/tauri/../../tr3ysmith)) Added conditional logic to MacOS codesigning where only executables get the entitlements file when being signed. This solves an issue where the app may not launch when using 3rd party frameworks if certain entitlements are added. Ex: multicast support (must be applied for through apple developer, and the framework would not have that capability).
|
||||
- [`0b79af711`](https://www.github.com/tauri-apps/tauri/commit/0b79af711430934362602fb950c3e4cb5b59cf9c) ([#12438](https://www.github.com/tauri-apps/tauri/pull/12438) by [@3lpsy](https://www.github.com/tauri-apps/tauri/../../3lpsy)) Log the command used to start the rust app in development.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- [`bc43c738b`](https://www.github.com/tauri-apps/tauri/commit/bc43c738baf686353690d3d9259b4976881718c8) ([#12442](https://www.github.com/tauri-apps/tauri/pull/12442) by [@FabianLars](https://www.github.com/tauri-apps/tauri/../../FabianLars)) Fixed an issue that prevented `tauri add` to work for the `clipboard-manager` plugin.
|
||||
- [`27096cdc0`](https://www.github.com/tauri-apps/tauri/commit/27096cdc05d89b61b2372b4e4a3018c87f240ab8) ([#12445](https://www.github.com/tauri-apps/tauri/pull/12445) by [@FabianLars](https://www.github.com/tauri-apps/tauri/../../FabianLars)) Fixed an issue that caused Tauri's CLI to enable tauri's `native-tls` feature even though it wasn't needed. Moved `reqwest` to a mobile-only dependency in `tauri` and enabled its `rustls-tls` feature flag.
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `tauri-bundler@2.2.3`
|
||||
|
||||
## \[2.2.5]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `tauri-bundler@2.2.2`
|
||||
|
||||
## \[2.2.4]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tauri-cli"
|
||||
version = "2.2.4"
|
||||
version = "2.5.0"
|
||||
authors = ["Tauri Programme within The Commons Conservancy"]
|
||||
edition = "2021"
|
||||
rust-version = "1.77.2"
|
||||
@@ -36,7 +36,7 @@ name = "cargo-tauri"
|
||||
path = "src/main.rs"
|
||||
|
||||
[target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\", target_os = \"windows\", target_os = \"macos\"))".dependencies]
|
||||
cargo-mobile2 = { version = "0.17", default-features = false }
|
||||
cargo-mobile2 = { version = "0.20", default-features = false }
|
||||
|
||||
[dependencies]
|
||||
jsonrpsee = { version = "0.24", features = ["server"] }
|
||||
@@ -47,17 +47,18 @@ sublime_fuzzy = "0.7"
|
||||
clap_complete = "4"
|
||||
clap = { version = "4", features = ["derive", "env"] }
|
||||
anyhow = "1"
|
||||
tauri-bundler = { version = "2.2.1", default-features = false, path = "../tauri-bundler" }
|
||||
tauri-bundler = { version = "2.4.0", default-features = false, path = "../tauri-bundler" }
|
||||
colored = "2"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = { version = "1", features = ["preserve_order"] }
|
||||
json5 = "0.4"
|
||||
notify = "8"
|
||||
notify-debouncer-full = "0.5"
|
||||
shared_child = "1"
|
||||
duct = "0.13"
|
||||
toml_edit = { version = "0.22", features = ["serde"] }
|
||||
json-patch = "3"
|
||||
tauri-utils = { version = "2.1.1", path = "../tauri-utils", features = [
|
||||
tauri-utils = { version = "2.4.0", path = "../tauri-utils", features = [
|
||||
"isolation",
|
||||
"schema",
|
||||
"config-json5",
|
||||
@@ -70,12 +71,12 @@ tauri-utils-v1 = { version = "1", package = "tauri-utils", features = [
|
||||
"config-toml",
|
||||
] }
|
||||
toml = "0.8"
|
||||
jsonschema = "0.28"
|
||||
jsonschema = "0.30"
|
||||
handlebars = "6"
|
||||
include_dir = "0.7"
|
||||
minisign = "=0.7.3"
|
||||
base64 = "0.22"
|
||||
ureq = { version = "2", default-features = false, features = ["gzip"] }
|
||||
ureq = { version = "3", default-features = false, features = ["gzip"] }
|
||||
os_info = "3"
|
||||
semver = "1"
|
||||
regex = "1"
|
||||
@@ -98,7 +99,7 @@ serde-value = "0.7"
|
||||
itertools = "0.13"
|
||||
local-ip-address = "0.6"
|
||||
css-color = "0.2"
|
||||
resvg = "0.44.0"
|
||||
resvg = "0.45.0"
|
||||
dunce = "1"
|
||||
glob = "0.3"
|
||||
# 0.39 raised msrv to above 1.78 but 0.37+ can't compile on 1.77.2 either.
|
||||
@@ -132,7 +133,7 @@ libc = "0.2"
|
||||
|
||||
[target."cfg(target_os = \"macos\")".dependencies]
|
||||
plist = "1"
|
||||
tauri-macos-sign = { version = "2.0.1", path = "../tauri-macos-sign" }
|
||||
tauri-macos-sign = { version = "2.1.0", path = "../tauri-macos-sign" }
|
||||
object = { version = "0.36", default-features = false, features = [
|
||||
"macho",
|
||||
"read_core",
|
||||
@@ -148,4 +149,4 @@ native-tls = [
|
||||
"ureq/native-tls",
|
||||
]
|
||||
native-tls-vendored = ["native-tls", "tauri-bundler/native-tls-vendored"]
|
||||
rustls = ["tauri-bundler/rustls", "cargo-mobile2/rustls", "ureq/tls"]
|
||||
rustls = ["tauri-bundler/rustls", "cargo-mobile2/rustls", "ureq/rustls"]
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://schema.tauri.app/config/2.2.1",
|
||||
"$id": "https://schema.tauri.app/config/2.5.1",
|
||||
"title": "Config",
|
||||
"description": "The Tauri configuration object.\n It is read from a file where you can define your frontend assets,\n configure the bundler and define a tray icon.\n\n The configuration file is generated by the\n [`tauri init`](https://v2.tauri.app/reference/cli/#init) command that lives in\n your Tauri application source directory (src-tauri).\n\n Once generated, you may modify it at will to customize your Tauri application.\n\n ## File Formats\n\n By default, the configuration is defined as a JSON file named `tauri.conf.json`.\n\n Tauri also supports JSON5 and TOML files via the `config-json5` and `config-toml` Cargo features, respectively.\n The JSON5 file name must be either `tauri.conf.json` or `tauri.conf.json5`.\n The TOML file name is `Tauri.toml`.\n\n ## Platform-Specific Configuration\n\n In addition to the default configuration file, Tauri can\n read a platform-specific configuration from `tauri.linux.conf.json`,\n `tauri.windows.conf.json`, `tauri.macos.conf.json`, `tauri.android.conf.json` and `tauri.ios.conf.json`\n (or `Tauri.linux.toml`, `Tauri.windows.toml`, `Tauri.macos.toml`, `Tauri.android.toml` and `Tauri.ios.toml` if the `Tauri.toml` format is used),\n which gets merged with the main configuration object.\n\n ## Configuration Structure\n\n The configuration is composed of the following objects:\n\n - [`app`](#appconfig): The Tauri configuration\n - [`build`](#buildconfig): The build configuration\n - [`bundle`](#bundleconfig): The bundle configurations\n - [`plugins`](#pluginconfig): The plugins configuration\n\n Example tauri.config.json file:\n\n ```json\n {\n \"productName\": \"tauri-app\",\n \"version\": \"0.1.0\",\n \"build\": {\n \"beforeBuildCommand\": \"\",\n \"beforeDevCommand\": \"\",\n \"devUrl\": \"../dist\",\n \"frontendDist\": \"../dist\"\n },\n \"app\": {\n \"security\": {\n \"csp\": null\n },\n \"windows\": [\n {\n \"fullscreen\": false,\n \"height\": 600,\n \"resizable\": true,\n \"title\": \"Tauri App\",\n \"width\": 800\n }\n ]\n },\n \"bundle\": {},\n \"plugins\": {}\n }\n ```",
|
||||
"description": "The Tauri configuration object.\n It is read from a file where you can define your frontend assets,\n configure the bundler and define a tray icon.\n\n The configuration file is generated by the\n [`tauri init`](https://v2.tauri.app/reference/cli/#init) command that lives in\n your Tauri application source directory (src-tauri).\n\n Once generated, you may modify it at will to customize your Tauri application.\n\n ## File Formats\n\n By default, the configuration is defined as a JSON file named `tauri.conf.json`.\n\n Tauri also supports JSON5 and TOML files via the `config-json5` and `config-toml` Cargo features, respectively.\n The JSON5 file name must be either `tauri.conf.json` or `tauri.conf.json5`.\n The TOML file name is `Tauri.toml`.\n\n ## Platform-Specific Configuration\n\n In addition to the default configuration file, Tauri can\n read a platform-specific configuration from `tauri.linux.conf.json`,\n `tauri.windows.conf.json`, `tauri.macos.conf.json`, `tauri.android.conf.json` and `tauri.ios.conf.json`\n (or `Tauri.linux.toml`, `Tauri.windows.toml`, `Tauri.macos.toml`, `Tauri.android.toml` and `Tauri.ios.toml` if the `Tauri.toml` format is used),\n which gets merged with the main configuration object.\n\n ## Configuration Structure\n\n The configuration is composed of the following objects:\n\n - [`app`](#appconfig): The Tauri configuration\n - [`build`](#buildconfig): The build configuration\n - [`bundle`](#bundleconfig): The bundle configurations\n - [`plugins`](#pluginconfig): The plugins configuration\n\n Example tauri.config.json file:\n\n ```json\n {\n \"productName\": \"tauri-app\",\n \"version\": \"0.1.0\",\n \"build\": {\n \"beforeBuildCommand\": \"\",\n \"beforeDevCommand\": \"\",\n \"devUrl\": \"http://localhost:3000\",\n \"frontendDist\": \"../dist\"\n },\n \"app\": {\n \"security\": {\n \"csp\": null\n },\n \"windows\": [\n {\n \"fullscreen\": false,\n \"height\": 600,\n \"resizable\": true,\n \"title\": \"Tauri App\",\n \"width\": 800\n }\n ]\n },\n \"bundle\": {},\n \"plugins\": {}\n }\n ```",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"identifier"
|
||||
@@ -31,7 +31,7 @@
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"description": "App version. It is a semver version number or a path to a `package.json` file containing the `version` field. If removed the version number from `Cargo.toml` is used.\n\n By default version 1.0 is used on Android.",
|
||||
"description": "App version. It is a semver version number or a path to a `package.json` file containing the `version` field.\n\n If removed the version number from `Cargo.toml` is used.\n It's recommended to manage the app versioning in the Tauri config.\n\n ## Platform-specific\n\n - **macOS**: Translates to the bundle's CFBundleShortVersionString property and is used as the default CFBundleVersion.\n You can set an specific bundle version using [`bundle > macOS > bundleVersion`](MacConfig::bundle_version).\n - **iOS**: Translates to the bundle's CFBundleShortVersionString property and is used as the default CFBundleVersion.\n You can set an specific bundle version using [`bundle > iOS > bundleVersion`](IosConfig::bundle_version).\n The `tauri ios build` CLI command has a `--build-number <number>` option that lets you append a build number to the app version.\n - **Android**: By default version 1.0 is used. You can set a version code using [`bundle > android > versionCode`](AndroidConfig::version_code).\n\n By default version 1.0 is used on Android.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
@@ -69,7 +69,9 @@
|
||||
},
|
||||
"build": {
|
||||
"description": "The build configuration.",
|
||||
"default": {},
|
||||
"default": {
|
||||
"removeUnusedCommands": false
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/BuildConfig"
|
||||
@@ -227,7 +229,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"create": {
|
||||
"description": "Whether Tauri should create this window at app startup or not.\n\n When this is set to `false` you must manually grab the config object via `app.config().app.windows`\n and create it with [`WebviewWindowBuilder::from_config`](https://docs.rs/tauri/2.0.0-rc/tauri/webview/struct.WebviewWindowBuilder.html#method.from_config).",
|
||||
"description": "Whether Tauri should create this window at app startup or not.\n\n When this is set to `false` you must manually grab the config object via `app.config().app.windows`\n and create it with [`WebviewWindowBuilder::from_config`](https://docs.rs/tauri/2/tauri/webview/struct.WebviewWindowBuilder.html#method.from_config).",
|
||||
"default": true,
|
||||
"type": "boolean"
|
||||
},
|
||||
@@ -317,6 +319,17 @@
|
||||
],
|
||||
"format": "double"
|
||||
},
|
||||
"preventOverflow": {
|
||||
"description": "Whether or not to prevent the window from overflowing the workarea\n\n ## Platform-specific\n\n - **iOS / Android:** Unsupported.",
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/PreventOverflowConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"resizable": {
|
||||
"description": "Whether the window is resizable or not. When resizable is set to false, native window's maximize button is automatically disabled.",
|
||||
"default": true,
|
||||
@@ -424,6 +437,17 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"trafficLightPosition": {
|
||||
"description": "The position of the window controls on macOS.\n\n Requires titleBarStyle: Overlay and decorations: true.",
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/LogicalPosition"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"hiddenTitle": {
|
||||
"description": "If `true`, sets the window title to be hidden on macOS.",
|
||||
"default": false,
|
||||
@@ -516,6 +540,32 @@
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"backgroundThrottling": {
|
||||
"description": "Change the default background throttling behaviour.\n\n By default, browsers use a suspend policy that will throttle timers and even unload\n the whole tab (view) to free resources after roughly 5 minutes when a view became\n minimized or hidden. This will pause all tasks until the documents visibility state\n changes back from hidden to visible by bringing the view back to the foreground.\n\n ## Platform-specific\n\n - **Linux / Windows / Android**: Unsupported. Workarounds like a pending WebLock transaction might suffice.\n - **iOS**: Supported since version 17.0+.\n - **macOS**: Supported since version 14.0+.\n\n see https://github.com/tauri-apps/tauri/issues/5250#issuecomment-2569380578",
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/BackgroundThrottlingPolicy"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"javascriptDisabled": {
|
||||
"description": "Whether we should disable JavaScript code execution on the webview or not.",
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"allowLinkPreview": {
|
||||
"description": "on macOS and iOS there is a link preview on long pressing links, this is enabled by default.\n see https://docs.rs/objc2-web-kit/latest/objc2_web_kit/struct.WKWebView.html#method.allowsLinkPreview",
|
||||
"default": true,
|
||||
"type": "boolean"
|
||||
},
|
||||
"disableInputAccessoryView": {
|
||||
"description": "Allows disabling the input accessory view on iOS.\n\n The accessory view is the view that appears above the keyboard when a text input element is focused.\n It usually displays a view with \"Done\", \"Next\" buttons.",
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
@@ -539,6 +589,46 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"PreventOverflowConfig": {
|
||||
"description": "Prevent overflow with a margin",
|
||||
"anyOf": [
|
||||
{
|
||||
"description": "Enable prevent overflow or not",
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"description": "Enable prevent overflow with a margin\n so that the window's size + this margin won't overflow the workarea",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/PreventOverflowMargin"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"PreventOverflowMargin": {
|
||||
"description": "Enable prevent overflow with a margin\n so that the window's size + this margin won't overflow the workarea",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"height",
|
||||
"width"
|
||||
],
|
||||
"properties": {
|
||||
"width": {
|
||||
"description": "Horizontal margin in physical unit",
|
||||
"type": "integer",
|
||||
"format": "uint32",
|
||||
"minimum": 0.0
|
||||
},
|
||||
"height": {
|
||||
"description": "Vertical margin in physical unit",
|
||||
"type": "integer",
|
||||
"format": "uint32",
|
||||
"minimum": 0.0
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Theme": {
|
||||
"description": "System theme.",
|
||||
"oneOf": [
|
||||
@@ -584,6 +674,27 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"LogicalPosition": {
|
||||
"description": "Position coordinates struct.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"x",
|
||||
"y"
|
||||
],
|
||||
"properties": {
|
||||
"x": {
|
||||
"description": "X coordinate.",
|
||||
"type": "number",
|
||||
"format": "double"
|
||||
},
|
||||
"y": {
|
||||
"description": "Y coordinate.",
|
||||
"type": "number",
|
||||
"format": "double"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"WindowEffectsConfig": {
|
||||
"description": "The window effects configuration object",
|
||||
"type": "object",
|
||||
@@ -948,6 +1059,32 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"BackgroundThrottlingPolicy": {
|
||||
"description": "Background throttling policy.",
|
||||
"oneOf": [
|
||||
{
|
||||
"description": "A policy where background throttling is disabled",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"disabled"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "A policy where a web view that’s not in a window fully suspends tasks. This is usually the default behavior in case no policy is set.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"suspend"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "A policy where a web view that’s not in a window limits processing, but does not fully suspend tasks.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"throttle"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"SecurityConfig": {
|
||||
"description": "Security configuration.\n\n See more: <https://v2.tauri.app/reference/config/#securityconfig>",
|
||||
"type": "object",
|
||||
@@ -1209,7 +1346,7 @@
|
||||
]
|
||||
},
|
||||
"Capability": {
|
||||
"description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\n It controls application windows fine grained access to the Tauri core, application, or plugin commands.\n If a window is not matching any capability then it has no access to the IPC layer at all.\n\n This can be done to create groups of windows, based on their required system access, which can reduce\n impact of frontend vulnerabilities in less privileged windows.\n Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`.\n A Window can have none, one, or multiple associated capabilities.\n\n ## Example\n\n ```json\n {\n \"identifier\": \"main-user-files-write\",\n \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\",\n \"windows\": [\n \"main\"\n ],\n \"permissions\": [\n \"core:default\",\n \"dialog:open\",\n {\n \"identifier\": \"fs:allow-write-text-file\",\n \"allow\": [{ \"path\": \"$HOME/test.txt\" }]\n },\n ],\n \"platforms\": [\"macOS\",\"windows\"]\n }\n ```",
|
||||
"description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\n It controls application windows' and webviews' fine grained access\n to the Tauri core, application, or plugin commands.\n If a webview or its window is not matching any capability then it has no access to the IPC layer at all.\n\n This can be done to create groups of windows, based on their required system access, which can reduce\n impact of frontend vulnerabilities in less privileged windows.\n Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`.\n A Window can have none, one, or multiple associated capabilities.\n\n ## Example\n\n ```json\n {\n \"identifier\": \"main-user-files-write\",\n \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\",\n \"windows\": [\n \"main\"\n ],\n \"permissions\": [\n \"core:default\",\n \"dialog:open\",\n {\n \"identifier\": \"fs:allow-write-text-file\",\n \"allow\": [{ \"path\": \"$HOME/test.txt\" }]\n },\n ],\n \"platforms\": [\"macOS\",\"windows\"]\n }\n ```",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"identifier",
|
||||
@@ -1242,14 +1379,14 @@
|
||||
"type": "boolean"
|
||||
},
|
||||
"windows": {
|
||||
"description": "List of windows that are affected by this capability. Can be a glob pattern.\n\n On multiwebview windows, prefer [`Self::webviews`] for a fine grained access control.\n\n ## Example\n\n `[\"main\"]`",
|
||||
"description": "List of windows that are affected by this capability. Can be a glob pattern.\n\n If a window label matches any of the patterns in this list,\n the capability will be enabled on all the webviews of that window,\n regardless of the value of [`Self::webviews`].\n\n On multiwebview windows, prefer specifying [`Self::webviews`] and omitting [`Self::windows`]\n for a fine grained access control.\n\n ## Example\n\n `[\"main\"]`",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"webviews": {
|
||||
"description": "List of webviews that are affected by this capability. Can be a glob pattern.\n\n This is only required when using on multiwebview contexts, by default\n all child webviews of a window that matches [`Self::windows`] are linked.\n\n ## Example\n\n `[\"sub-webview-one\", \"sub-webview-two\"]`",
|
||||
"description": "List of webviews that are affected by this capability. Can be a glob pattern.\n\n The capability will be enabled on all the webviews\n whose label matches any of the patterns in this list,\n regardless of whether the webview's window label matches a pattern in [`Self::windows`].\n\n ## Example\n\n `[\"sub-webview-one\", \"sub-webview-two\"]`",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
@@ -1439,7 +1576,7 @@
|
||||
]
|
||||
},
|
||||
"HeaderConfig": {
|
||||
"description": "A struct, where the keys are some specific http header names.\n If the values to those keys are defined, then they will be send as part of a response message.\n This does not include error messages and ipc messages\n\n ## Example configuration\n ```javascript\n {\n //..\n app:{\n //..\n security: {\n headers: {\n \"Cross-Origin-Opener-Policy\": \"same-origin\",\n \"Cross-Origin-Embedder-Policy\": \"require-corp\",\n \"Timing-Allow-Origin\": [\n \"https://developer.mozilla.org\",\n \"https://example.com\",\n ],\n \"Access-Control-Expose-Headers\": \"Tauri-Custom-Header\",\n \"Tauri-Custom-Header\": {\n \"key1\": \"'value1' 'value2'\",\n \"key2\": \"'value3'\"\n }\n },\n csp: \"default-src 'self'; connect-src ipc: http://ipc.localhost\",\n }\n //..\n }\n //..\n }\n ```\n In this example `Cross-Origin-Opener-Policy` and `Cross-Origin-Embedder-Policy` are set to allow for the use of [`SharedArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer).\n The result is, that those headers are then set on every response sent via the `get_response` function in crates/tauri/src/protocol/tauri.rs.\n The Content-Security-Policy header is defined separately, because it is also handled separately.\n\n For the helloworld example, this config translates into those response headers:\n ```http\n access-control-allow-origin: http://tauri.localhost\n access-control-expose-headers: Tauri-Custom-Header\n content-security-policy: default-src 'self'; connect-src ipc: http://ipc.localhost; script-src 'self' 'sha256-Wjjrs6qinmnr+tOry8x8PPwI77eGpUFR3EEGZktjJNs='\n content-type: text/html\n cross-origin-embedder-policy: require-corp\n cross-origin-opener-policy: same-origin\n tauri-custom-header: key1 'value1' 'value2'; key2 'value3'\n timing-allow-origin: https://developer.mozilla.org, https://example.com\n ```\n Since the resulting header values are always 'string-like'. So depending on the what data type the HeaderSource is, they need to be converted.\n - `String`(JS/Rust): stay the same for the resulting header value\n - `Array`(JS)/`Vec\\<String\\>`(Rust): Item are joined by \", \" for the resulting header value\n - `Object`(JS)/ `Hashmap\\<String,String\\>`(Rust): Items are composed from: key + space + value. Item are then joined by \"; \" for the resulting header value",
|
||||
"description": "A struct, where the keys are some specific http header names.\n\n If the values to those keys are defined, then they will be send as part of a response message.\n This does not include error messages and ipc messages\n\n ## Example configuration\n ```javascript\n {\n //..\n app:{\n //..\n security: {\n headers: {\n \"Cross-Origin-Opener-Policy\": \"same-origin\",\n \"Cross-Origin-Embedder-Policy\": \"require-corp\",\n \"Timing-Allow-Origin\": [\n \"https://developer.mozilla.org\",\n \"https://example.com\",\n ],\n \"Access-Control-Expose-Headers\": \"Tauri-Custom-Header\",\n \"Tauri-Custom-Header\": {\n \"key1\": \"'value1' 'value2'\",\n \"key2\": \"'value3'\"\n }\n },\n csp: \"default-src 'self'; connect-src ipc: http://ipc.localhost\",\n }\n //..\n }\n //..\n }\n ```\n In this example `Cross-Origin-Opener-Policy` and `Cross-Origin-Embedder-Policy` are set to allow for the use of [`SharedArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer).\n The result is, that those headers are then set on every response sent via the `get_response` function in crates/tauri/src/protocol/tauri.rs.\n The Content-Security-Policy header is defined separately, because it is also handled separately.\n\n For the helloworld example, this config translates into those response headers:\n ```http\n access-control-allow-origin: http://tauri.localhost\n access-control-expose-headers: Tauri-Custom-Header\n content-security-policy: default-src 'self'; connect-src ipc: http://ipc.localhost; script-src 'self' 'sha256-Wjjrs6qinmnr+tOry8x8PPwI77eGpUFR3EEGZktjJNs='\n content-type: text/html\n cross-origin-embedder-policy: require-corp\n cross-origin-opener-policy: same-origin\n tauri-custom-header: key1 'value1' 'value2'; key2 'value3'\n timing-allow-origin: https://developer.mozilla.org, https://example.com\n ```\n Since the resulting header values are always 'string-like'. So depending on the what data type the HeaderSource is, they need to be converted.\n - `String`(JS/Rust): stay the same for the resulting header value\n - `Array`(JS)/`Vec\\<String\\>`(Rust): Item are joined by \", \" for the resulting header value\n - `Object`(JS)/ `Hashmap\\<String,String\\>`(Rust): Items are composed from: key + space + value. Item are then joined by \"; \" for the resulting header value",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"Access-Control-Allow-Credentials": {
|
||||
@@ -1541,6 +1678,17 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"Service-Worker-Allowed": {
|
||||
"description": "The HTTP Service-Worker-Allowed response header is used to broaden the path restriction for a\n service worker's default scope.\n\n By default, the scope for a service worker registration is the directory where the service\n worker script is located. For example, if the script `sw.js` is located in `/js/sw.js`,\n it can only control URLs under `/js/` by default. Servers can use the `Service-Worker-Allowed`\n header to allow a service worker to control URLs outside of its own directory.\n\n See <https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Service-Worker-Allowed>",
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/HeaderSource"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Timing-Allow-Origin": {
|
||||
"description": "The Timing-Allow-Origin response header specifies origins that are allowed to see values\n of attributes retrieved via features of the Resource Timing API, which would otherwise be\n reported as zero due to cross-origin restrictions.\n\n See <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Timing-Allow-Origin>",
|
||||
"anyOf": [
|
||||
@@ -1663,7 +1811,7 @@
|
||||
]
|
||||
},
|
||||
"devUrl": {
|
||||
"description": "The URL to load in development.\n\n This is usually an URL to a dev server, which serves your application assets with hot-reload and HMR.\n Most modern JavaScript bundlers like [vite](https://vitejs.dev/guide/) provides a way to start a dev server by default.\n\n If you don't have a dev server or don't want to use one, ignore this option and use [`frontendDist`](BuildConfig::frontend_dist)\n and point to a web assets directory, and Tauri CLI will run its built-in dev server and provide a simple hot-reload experience.",
|
||||
"description": "The URL to load in development.\n\n This is usually an URL to a dev server, which serves your application assets with hot-reload and HMR.\n Most modern JavaScript bundlers like [Vite](https://vite.dev/guide/) provides a way to start a dev server by default.\n\n If you don't have a dev server or don't want to use one, ignore this option and use [`frontendDist`](BuildConfig::frontend_dist)\n and point to a web assets directory, and Tauri CLI will run its built-in dev server and provide a simple hot-reload experience.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
@@ -1723,6 +1871,11 @@
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"removeUnusedCommands": {
|
||||
"description": "Try to remove unused commands registered from plugins base on the ACL list during `tauri build`,\n the way it works is that tauri-cli will read this and set the environment variables for the build script and macros,\n and they'll try to get all the allowed commands and remove the rest\n\n Note:\n - This won't be accounting for dynamically added ACLs so make sure to check it when using this\n - This feature requires tauri-plugin 2.1 and tauri 2.4",
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
@@ -1924,7 +2077,7 @@
|
||||
]
|
||||
},
|
||||
"useLocalToolsDir": {
|
||||
"description": "Whether to use the project's `target` directory, for caching build tools (e.g., Wix and NSIS) when building this application. Defaults to `false`.\n\n If true, tools will be cached in `target\\.tauri-tools`.\n If false, tools will be cached in the current user's platform-specific cache directory.\n\n An example where it can be appropriate to set this to `true` is when building this application as a Windows System user (e.g., AWS EC2 workloads),\n because the Window system's app data directory is restricted.",
|
||||
"description": "Whether to use the project's `target` directory, for caching build tools (e.g., Wix and NSIS) when building this application. Defaults to `false`.\n\n If true, tools will be cached in `target/.tauri/`.\n If false, tools will be cached in the current user's platform-specific cache directory.\n\n An example where it can be appropriate to set this to `true` is when building this application as a Windows System user (e.g., AWS EC2 workloads),\n because the Window system's app data directory is restricted.",
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
@@ -2203,6 +2356,15 @@
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"rank": {
|
||||
"description": "The ranking of this app among apps that declare themselves as editors or viewers of the given file type. Maps to `LSHandlerRank` on macOS.",
|
||||
"default": "Default",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/HandlerRank"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
@@ -2251,6 +2413,39 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"HandlerRank": {
|
||||
"description": "Corresponds to LSHandlerRank",
|
||||
"oneOf": [
|
||||
{
|
||||
"description": "LSHandlerRank.Default. This app is an opener of files of this type; this value is also used if no rank is specified.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Default"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "LSHandlerRank.Owner. This app is the primary creator of files of this type.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Owner"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "LSHandlerRank.Alternate. This app is a secondary viewer of files of this type.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Alternate"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "LSHandlerRank.None. This app is never selected to open files of this type, but it accepts drops of files of this type.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"None"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"WindowsConfig": {
|
||||
"description": "Windows bundler configuration.\n\n See more: <https://v2.tauri.app/reference/config/#windowsconfig>",
|
||||
"type": "object",
|
||||
@@ -3211,6 +3406,13 @@
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"bundleVersion": {
|
||||
"description": "The version of the build that identifies an iteration of the bundle.\n\n Translates to the bundle's CFBundleVersion property.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"minimumSystemVersion": {
|
||||
"description": "A version string indicating the minimum macOS X version that the bundled application supports. Defaults to `10.13`.\n\n Setting it to `null` completely removes the `LSMinimumSystemVersion` field on the bundle's `Info.plist`\n and the `MACOSX_DEPLOYMENT_TARGET` environment variable.\n\n An empty string is considered an invalid value so the default value is used.",
|
||||
"default": "10.13",
|
||||
@@ -3412,6 +3614,13 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"bundleVersion": {
|
||||
"description": "The version of the build that identifies an iteration of the bundle.\n\n Translates to the bundle's CFBundleVersion property.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"minimumSystemVersion": {
|
||||
"description": "A version string indicating the minimum iOS version that the bundled application supports. Defaults to `13.0`.\n\n Maps to the IPHONEOS_DEPLOYMENT_TARGET value.",
|
||||
"default": "13.0",
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"cli.js": {
|
||||
"version": "2.2.4",
|
||||
"version": "2.5.0",
|
||||
"node": ">= 10.0.0"
|
||||
},
|
||||
"tauri": "2.2.1",
|
||||
"tauri-build": "2.0.4",
|
||||
"tauri-plugin": "2.0.3"
|
||||
"tauri": "2.5.1",
|
||||
"tauri-build": "2.2.0",
|
||||
"tauri-plugin": "2.2.0"
|
||||
}
|
||||
|
||||
@@ -301,6 +301,17 @@
|
||||
],
|
||||
"format": "double"
|
||||
},
|
||||
"preventOverflow": {
|
||||
"description": "Whether or not to prevent window overflow",
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/PreventOverflowMarginConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"resizable": {
|
||||
"description": "Whether the window is resizable or not. When resizable is set to false, native window's maximize button is automatically disabled.",
|
||||
"default": true,
|
||||
@@ -465,6 +476,15 @@
|
||||
"description": "Whether page zooming by hotkeys is enabled\n\n ## Platform-specific:\n\n - **Windows**: Controls WebView2's [`IsZoomControlEnabled`](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/winrt/microsoft_web_webview2_core/corewebview2settings?view=webview2-winrt-1.0.2420.47#iszoomcontrolenabled) setting.\n - **MacOS / Linux**: Injects a polyfill that zooms in and out with `ctrl/command` + `-/=`,\n 20% in each step, ranging from 20% to 1000%. Requires `webview:allow-set-webview-zoom` permission\n\n - **Android / iOS**: Unsupported.",
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"backgroundThrottling": {
|
||||
"description": "Change the default background throttling behaviour.\n\n By default, browsers use a suspend policy that will throttle timers and even unload\n the whole tab (view) to free resources after roughly 5 minutes when a view became\n minimized or hidden. This will pause all tasks until the documents visibility state\n changes back from hidden to visible by bringing the view back to the foreground.\n\n ## Platform-specific\n\n - **Linux / Windows / Android**: Unsupported. Workarounds like a pending WebLock transaction might suffice.\n - **iOS**: Supported since version 17.0+.\n - **macOS**: Supported since version 14.0+.\n\n see https://github.com/tauri-apps/tauri/issues/5250#issuecomment-2569380578",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"disabled",
|
||||
"throttle",
|
||||
"suspend"
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
@@ -488,6 +508,46 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"PreventOverflowMarginConfig": {
|
||||
"description": "Prevent overflow with a margin",
|
||||
"anyOf": [
|
||||
{
|
||||
"description": "Enable prevent overflow or not",
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"description": "Enable prevent overflow with a margin",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/PreventOverflowMargin"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"PreventOverflowMargin": {
|
||||
"description": "Enable prevent overflow with a margin",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"height",
|
||||
"width"
|
||||
],
|
||||
"properties": {
|
||||
"width": {
|
||||
"description": "Horizontal margin in physical unit",
|
||||
"type": "integer",
|
||||
"format": "uint32",
|
||||
"minimum": 0.0
|
||||
},
|
||||
"height": {
|
||||
"description": "Vertical margin in physical unit",
|
||||
"type": "integer",
|
||||
"format": "uint32",
|
||||
"minimum": 0.0
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Theme": {
|
||||
"description": "System theme.",
|
||||
"oneOf": [
|
||||
@@ -1369,7 +1429,7 @@
|
||||
]
|
||||
},
|
||||
"devUrl": {
|
||||
"description": "The URL to load in development.\n\n This is usually an URL to a dev server, which serves your application assets with hot-reload and HMR.\n Most modern JavaScript bundlers like [vite](https://vitejs.dev/guide/) provides a way to start a dev server by default.\n\n If you don't have a dev server or don't want to use one, ignore this option and use [`frontendDist`](BuildConfig::frontend_dist)\n and point to a web assets directory, and Tauri CLI will run its built-in dev server and provide a simple hot-reload experience.",
|
||||
"description": "The URL to load in development.\n\n This is usually an URL to a dev server, which serves your application assets with hot-reload and HMR.\n Most modern JavaScript bundlers like [Vite](https://vite.dev/guide/) provides a way to start a dev server by default.\n\n If you don't have a dev server or don't want to use one, ignore this option and use [`frontendDist`](BuildConfig::frontend_dist)\n and point to a web assets directory, and Tauri CLI will run its built-in dev server and provide a simple hot-reload experience.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
@@ -1906,6 +1966,15 @@
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"rank": {
|
||||
"description": "The ranking of this app among apps that declare themselves as editors or viewers of the given file type. Maps to `LSHandlerRank` on macOS.",
|
||||
"default": "Default",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/HandlerRank"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
@@ -1954,6 +2023,39 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"HandlerRank": {
|
||||
"description": "Corresponds to LSHandlerRank",
|
||||
"oneOf": [
|
||||
{
|
||||
"description": "LSHandlerRank.Default. This app is an opener of files of this type; this value is also used if no rank is specified.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Default"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "LSHandlerRank.Owner. This app is the primary creator of files of this type.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Owner"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "LSHandlerRank.Alternate. This app is a secondary viewer of files of this type.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Alternate"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "LSHandlerRank.None. This app is never selected to open files of this type, but it accepts drops of files of this type.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"None"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"WindowsConfig": {
|
||||
"description": "Windows bundler configuration.\n\n See more: <https://tauri.app/v1/api/config#windowsconfig>",
|
||||
"type": "object",
|
||||
|
||||
@@ -9,12 +9,12 @@ use crate::{
|
||||
app_paths::tauri_dir,
|
||||
config::{get as get_config, ConfigHandle, FrontendDist},
|
||||
},
|
||||
interface::{AppInterface, Interface},
|
||||
interface::{rust::get_cargo_target_dir, AppInterface, Interface},
|
||||
ConfigValue, Result,
|
||||
};
|
||||
use anyhow::Context;
|
||||
use clap::{ArgAction, Parser};
|
||||
use std::env::set_current_dir;
|
||||
use std::{env::set_current_dir, fs};
|
||||
use tauri_utils::platform::Target;
|
||||
|
||||
#[derive(Debug, Clone, Parser)]
|
||||
@@ -40,16 +40,20 @@ pub struct Options {
|
||||
#[clap(short, long, action = ArgAction::Append, num_args(0..))]
|
||||
pub features: Option<Vec<String>>,
|
||||
/// Space or comma separated list of bundles to package.
|
||||
///
|
||||
/// Note that the `updater` bundle is not automatically added so you must specify it if the updater is enabled.
|
||||
#[clap(short, long, action = ArgAction::Append, num_args(0..), value_delimiter = ',')]
|
||||
pub bundles: Option<Vec<BundleFormat>>,
|
||||
/// Skip the bundling step even if `bundle > active` is `true` in tauri config.
|
||||
#[clap(long)]
|
||||
pub no_bundle: bool,
|
||||
/// JSON string or path to JSON file to merge with tauri.conf.json
|
||||
/// 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.
|
||||
///
|
||||
/// Note that a platform-specific file is looked up and merged with the default file by default
|
||||
/// (tauri.macos.conf.json, tauri.linux.conf.json, tauri.windows.conf.json, tauri.android.conf.json and tauri.ios.conf.json)
|
||||
/// but you can use this for more specific use cases such as different build flavors.
|
||||
#[clap(short, long)]
|
||||
pub config: Option<ConfigValue>,
|
||||
pub config: Vec<ConfigValue>,
|
||||
/// Command line arguments passed to the runner. Use `--` to explicitly mark the start of the arguments.
|
||||
pub args: Vec<String>,
|
||||
/// Skip prompting for values
|
||||
@@ -68,7 +72,10 @@ pub fn command(mut options: Options, verbosity: u8) -> Result<()> {
|
||||
.map(Target::from_triple)
|
||||
.unwrap_or_else(Target::current);
|
||||
|
||||
let config = get_config(target, options.config.as_ref().map(|c| &c.0))?;
|
||||
let config = get_config(
|
||||
target,
|
||||
&options.config.iter().map(|c| &c.0).collect::<Vec<_>>(),
|
||||
)?;
|
||||
|
||||
let mut interface = AppInterface::new(
|
||||
config.lock().unwrap().as_ref().unwrap(),
|
||||
@@ -165,19 +172,32 @@ 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 = fs::canonicalize(get_cargo_target_dir(&options.args)?)?;
|
||||
let mut out_folders = Vec::new();
|
||||
for folder in &["node_modules", "src-tauri", "target"] {
|
||||
if web_asset_path.join(folder).is_dir() {
|
||||
out_folders.push(folder.to_string());
|
||||
if let Ok(web_asset_canonical) = web_asset_path.canonicalize() {
|
||||
if let Ok(relative_path) = target_path.strip_prefix(&web_asset_canonical) {
|
||||
let relative_str = relative_path.to_string_lossy();
|
||||
if !relative_str.is_empty() {
|
||||
out_folders.push(relative_str.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
for folder in &["node_modules", "src-tauri"] {
|
||||
let sub_path = web_asset_canonical.join(folder);
|
||||
if sub_path.is_dir() {
|
||||
out_folders.push(folder.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !out_folders.is_empty() {
|
||||
return Err(anyhow::anyhow!(
|
||||
"The configured frontendDist includes the `{:?}` {}. Please isolate your web assets on a separate folder and update `tauri.conf.json > build > frontendDist`.",
|
||||
out_folders,
|
||||
if out_folders.len() == 1 { "folder" }else { "folders" }
|
||||
)
|
||||
);
|
||||
"The configured frontendDist includes the `{:?}` {}. Please isolate your web assets on a separate folder and update `tauri.conf.json > build > frontendDist`.",
|
||||
out_folders,
|
||||
if out_folders.len() == 1 { "folder" } else { "folders" }
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,8 @@ impl ValueEnum for BundleFormat {
|
||||
}
|
||||
|
||||
fn to_possible_value(&self) -> Option<PossibleValue> {
|
||||
Some(PossibleValue::new(self.0.short_name()))
|
||||
let hide = self.0 == PackageType::Updater;
|
||||
Some(PossibleValue::new(self.0.short_name()).hide(hide))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,13 +58,17 @@ pub struct Options {
|
||||
#[clap(short, long)]
|
||||
pub debug: bool,
|
||||
/// Space or comma separated list of bundles to package.
|
||||
///
|
||||
/// Note that the `updater` bundle is not automatically added so you must specify it if the updater is enabled.
|
||||
#[clap(short, long, action = ArgAction::Append, num_args(0..), value_delimiter = ',')]
|
||||
pub bundles: Option<Vec<BundleFormat>>,
|
||||
/// JSON string or path to JSON file to merge with tauri.conf.json
|
||||
/// 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.
|
||||
///
|
||||
/// Note that a platform-specific file is looked up and merged with the default file by default
|
||||
/// (tauri.macos.conf.json, tauri.linux.conf.json, tauri.windows.conf.json, tauri.android.conf.json and tauri.ios.conf.json)
|
||||
/// but you can use this for more specific use cases such as different build flavors.
|
||||
#[clap(short, long)]
|
||||
pub config: Option<ConfigValue>,
|
||||
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>>,
|
||||
@@ -103,7 +108,10 @@ pub fn command(options: Options, verbosity: u8) -> crate::Result<()> {
|
||||
.map(Target::from_triple)
|
||||
.unwrap_or_else(Target::current);
|
||||
|
||||
let config = get_config(target, options.config.as_ref().map(|c| &c.0))?;
|
||||
let config = get_config(
|
||||
target,
|
||||
&options.config.iter().map(|c| &c.0).collect::<Vec<_>>(),
|
||||
)?;
|
||||
|
||||
let interface = AppInterface::new(
|
||||
config.lock().unwrap().as_ref().unwrap(),
|
||||
@@ -213,6 +221,7 @@ fn sign_updaters(
|
||||
| PackageType::WindowsMsi
|
||||
| PackageType::AppImage
|
||||
| PackageType::Deb
|
||||
| PackageType::Rpm
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
@@ -59,9 +59,15 @@ pub struct Options {
|
||||
/// Exit on panic
|
||||
#[clap(short, long)]
|
||||
pub exit_on_panic: bool,
|
||||
/// JSON string or path to JSON file to merge with tauri.conf.json
|
||||
/// 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.
|
||||
///
|
||||
/// Note that a platform-specific file is looked up and merged with the default file by default
|
||||
/// (tauri.macos.conf.json, tauri.linux.conf.json, tauri.windows.conf.json, tauri.android.conf.json and tauri.ios.conf.json)
|
||||
/// but you can use this for more specific use cases such as different build flavors.
|
||||
#[clap(short, long)]
|
||||
pub config: Option<ConfigValue>,
|
||||
pub config: Vec<ConfigValue>,
|
||||
/// Run the code in release mode
|
||||
#[clap(long = "release")]
|
||||
pub release_mode: bool,
|
||||
@@ -104,7 +110,10 @@ fn command_internal(mut options: Options) -> Result<()> {
|
||||
.map(Target::from_triple)
|
||||
.unwrap_or_else(Target::current);
|
||||
|
||||
let config = get_config(target, options.config.as_ref().map(|c| &c.0))?;
|
||||
let config = get_config(
|
||||
target,
|
||||
&options.config.iter().map(|c| &c.0).collect::<Vec<_>>(),
|
||||
)?;
|
||||
|
||||
let mut interface = AppInterface::new(
|
||||
config.lock().unwrap().as_ref().unwrap(),
|
||||
@@ -262,26 +271,13 @@ pub fn setup(interface: &AppInterface, options: &mut Options, config: ConfigHand
|
||||
let server_url = format!("http://{server_url}");
|
||||
dev_url = Some(server_url.parse().unwrap());
|
||||
|
||||
if let Some(c) = &mut options.config {
|
||||
if let Some(build) = c
|
||||
.0
|
||||
.as_object_mut()
|
||||
.and_then(|root| root.get_mut("build"))
|
||||
.and_then(|build| build.as_object_mut())
|
||||
{
|
||||
build.insert("devUrl".into(), server_url.into());
|
||||
options.config.push(crate::ConfigValue(serde_json::json!({
|
||||
"build": {
|
||||
"devUrl": server_url
|
||||
}
|
||||
} else {
|
||||
options
|
||||
.config
|
||||
.replace(crate::ConfigValue(serde_json::json!({
|
||||
"build": {
|
||||
"devUrl": server_url
|
||||
}
|
||||
})));
|
||||
}
|
||||
})));
|
||||
|
||||
reload_config(options.config.as_ref().map(|c| &c.0))?;
|
||||
reload_config(&options.config.iter().map(|c| &c.0).collect::<Vec<_>>())?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ pub fn start<P: AsRef<Path>>(dir: P, ip: IpAddr, port: Option<u16>) -> crate::Re
|
||||
}
|
||||
|
||||
async fn handler(uri: Uri, state: State<ServerState>) -> impl IntoResponse {
|
||||
// Frontend files should not contain query parameters. This seems to be how vite handles it.
|
||||
// Frontend files should not contain query parameters. This seems to be how Vite handles it.
|
||||
let uri = uri.path();
|
||||
|
||||
let uri = if uri == "/" {
|
||||
|
||||
@@ -39,6 +39,7 @@ pub fn walk_builder(path: &Path) -> WalkBuilder {
|
||||
let mut builder = WalkBuilder::new(path);
|
||||
builder.add_custom_ignore_filename(".taurignore");
|
||||
builder.git_global(false);
|
||||
builder.parents(false);
|
||||
let _ = builder.add_ignore(default_gitignore);
|
||||
builder
|
||||
}
|
||||
@@ -94,20 +95,36 @@ fn env_tauri_frontend_path() -> Option<PathBuf> {
|
||||
pub fn resolve_tauri_dir() -> Option<PathBuf> {
|
||||
let src_dir = env_tauri_app_path().or_else(|| current_dir().ok())?;
|
||||
|
||||
if src_dir.join(ConfigFormat::Json.into_file_name()).exists()
|
||||
|| src_dir.join(ConfigFormat::Json5.into_file_name()).exists()
|
||||
|| src_dir.join(ConfigFormat::Toml.into_file_name()).exists()
|
||||
{
|
||||
return Some(src_dir);
|
||||
for standard_tauri_path in [src_dir.clone(), src_dir.join("src-tauri")] {
|
||||
if standard_tauri_path
|
||||
.join(ConfigFormat::Json.into_file_name())
|
||||
.exists()
|
||||
|| standard_tauri_path
|
||||
.join(ConfigFormat::Json5.into_file_name())
|
||||
.exists()
|
||||
|| standard_tauri_path
|
||||
.join(ConfigFormat::Toml.into_file_name())
|
||||
.exists()
|
||||
{
|
||||
log::debug!(
|
||||
"Found Tauri project inside {} on early lookup",
|
||||
standard_tauri_path.display()
|
||||
);
|
||||
return Some(standard_tauri_path);
|
||||
}
|
||||
}
|
||||
|
||||
log::debug!("resolving Tauri directory from {}", src_dir.display());
|
||||
|
||||
lookup(&src_dir, |path| {
|
||||
folder_has_configuration_file(Target::Linux, path) || is_configuration_file(Target::Linux, path)
|
||||
})
|
||||
.map(|p| {
|
||||
if p.is_dir() {
|
||||
log::debug!("Found Tauri project directory {}", p.display());
|
||||
p
|
||||
} else {
|
||||
log::debug!("Found Tauri project configuration file {}", p.display());
|
||||
p.parent().unwrap().to_path_buf()
|
||||
}
|
||||
})
|
||||
@@ -142,6 +159,11 @@ pub fn resolve_frontend_dir() -> Option<PathBuf> {
|
||||
return Some(frontend_dir);
|
||||
}
|
||||
|
||||
log::debug!(
|
||||
"resolving frontend directory from {}",
|
||||
frontend_dir.display()
|
||||
);
|
||||
|
||||
lookup(&frontend_dir, |path| {
|
||||
if let Some(file_name) = path.file_name() {
|
||||
file_name == OsStr::new("package.json")
|
||||
|
||||
@@ -97,15 +97,30 @@ impl std::fmt::Display for CrateVersion {
|
||||
}
|
||||
}
|
||||
|
||||
// Reference: https://github.com/rust-lang/crates.io/blob/98c83c8231cbcd15d6b8f06d80a00ad462f71585/src/views.rs#L274
|
||||
#[derive(serde::Deserialize)]
|
||||
struct CrateMetadata {
|
||||
/// The "default" version of this crate.
|
||||
///
|
||||
/// This version will be displayed by default on the crate's page.
|
||||
pub default_version: Option<String>,
|
||||
}
|
||||
|
||||
// Reference: https://github.com/rust-lang/crates.io/blob/98c83c8231cbcd15d6b8f06d80a00ad462f71585/src/controllers/krate/metadata.rs#L44
|
||||
#[derive(serde::Deserialize)]
|
||||
struct CrateIoGetResponse {
|
||||
/// The crate metadata.
|
||||
#[serde(rename = "crate")]
|
||||
krate: CrateMetadata,
|
||||
}
|
||||
|
||||
pub fn crate_latest_version(name: &str) -> Option<String> {
|
||||
let url = format!("https://docs.rs/crate/{name}/");
|
||||
match ureq::get(&url).call() {
|
||||
Ok(response) => match (response.status(), response.header("location")) {
|
||||
(302, Some(location)) => Some(location.replace(&url, "")),
|
||||
_ => None,
|
||||
},
|
||||
Err(_) => None,
|
||||
}
|
||||
// Reference: https://github.com/rust-lang/crates.io/blob/98c83c8231cbcd15d6b8f06d80a00ad462f71585/src/controllers/krate/metadata.rs#L88
|
||||
let url = format!("https://crates.io/api/v1/crates/{name}?include");
|
||||
let mut response = ureq::get(&url).call().ok()?;
|
||||
let metadata: CrateIoGetResponse =
|
||||
serde_json::from_reader(response.body_mut().as_reader()).unwrap();
|
||||
metadata.krate.default_version
|
||||
}
|
||||
|
||||
pub fn crate_version(
|
||||
|
||||
@@ -6,6 +6,7 @@ use itertools::Itertools;
|
||||
use json_patch::merge;
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
use tauri_utils::acl::REMOVE_UNUSED_COMMANDS_ENV_VAR;
|
||||
pub use tauri_utils::{config::*, platform::Target};
|
||||
|
||||
use std::{
|
||||
@@ -138,7 +139,7 @@ fn config_handle() -> &'static ConfigHandle {
|
||||
|
||||
/// Gets the static parsed config from `tauri.conf.json`.
|
||||
fn get_internal(
|
||||
merge_config: Option<&serde_json::Value>,
|
||||
merge_configs: &[&serde_json::Value],
|
||||
reload: bool,
|
||||
target: Target,
|
||||
) -> crate::Result<ConfigHandle> {
|
||||
@@ -153,7 +154,7 @@ fn get_internal(
|
||||
let mut extensions = HashMap::new();
|
||||
|
||||
if let Some((platform_config, config_path)) =
|
||||
tauri_utils::config::parse::read_platform(target, tauri_dir.to_path_buf())?
|
||||
tauri_utils::config::parse::read_platform(target, tauri_dir)?
|
||||
{
|
||||
merge(&mut config, &platform_config);
|
||||
extensions.insert(
|
||||
@@ -162,12 +163,17 @@ fn get_internal(
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(merge_config) = merge_config {
|
||||
if !merge_configs.is_empty() {
|
||||
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);
|
||||
merge(&mut config, merge_config);
|
||||
extensions.insert(MERGE_CONFIG_EXTENSION_NAME.into(), merge_config.clone());
|
||||
};
|
||||
merge(&mut config, &merge_config);
|
||||
extensions.insert(MERGE_CONFIG_EXTENSION_NAME.into(), merge_config);
|
||||
}
|
||||
|
||||
if config_path.extension() == Some(OsStr::new("json"))
|
||||
|| config_path.extension() == Some(OsStr::new("json5"))
|
||||
@@ -208,6 +214,10 @@ fn get_internal(
|
||||
);
|
||||
}
|
||||
|
||||
if config.build.remove_unused_commands {
|
||||
std::env::set_var(REMOVE_UNUSED_COMMANDS_ENV_VAR, tauri_dir);
|
||||
}
|
||||
|
||||
*config_handle().lock().unwrap() = Some(ConfigMetadata {
|
||||
target,
|
||||
inner: config,
|
||||
@@ -217,35 +227,42 @@ fn get_internal(
|
||||
Ok(config_handle().clone())
|
||||
}
|
||||
|
||||
pub fn get(
|
||||
target: Target,
|
||||
merge_config: Option<&serde_json::Value>,
|
||||
) -> crate::Result<ConfigHandle> {
|
||||
get_internal(merge_config, false, target)
|
||||
pub fn get(target: Target, merge_configs: &[&serde_json::Value]) -> crate::Result<ConfigHandle> {
|
||||
get_internal(merge_configs, false, target)
|
||||
}
|
||||
|
||||
pub fn reload(merge_config: Option<&serde_json::Value>) -> crate::Result<ConfigHandle> {
|
||||
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_config, true, target)
|
||||
get_internal(merge_configs, true, target)
|
||||
} else {
|
||||
Err(anyhow::anyhow!("config not loaded"))
|
||||
}
|
||||
}
|
||||
|
||||
/// merges the loaded config with the given value
|
||||
pub fn merge_with(merge_config: &serde_json::Value) -> crate::Result<ConfigHandle> {
|
||||
pub fn merge_with(merge_configs: &[&serde_json::Value]) -> crate::Result<ConfigHandle> {
|
||||
let handle = config_handle();
|
||||
|
||||
if merge_configs.is_empty() {
|
||||
return Ok(handle.clone());
|
||||
}
|
||||
|
||||
if let Some(config_metadata) = &mut *handle.lock().unwrap() {
|
||||
let merge_config_str = serde_json::to_string(merge_config).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())?;
|
||||
merge(&mut value, merge_config);
|
||||
merge(&mut value, &merge_config);
|
||||
config_metadata.inner = serde_json::from_value(value)?;
|
||||
|
||||
Ok(handle.clone())
|
||||
@@ -253,3 +270,87 @@ pub fn merge_with(merge_config: &serde_json::Value) -> crate::Result<ConfigHandl
|
||||
Err(anyhow::anyhow!("config not loaded"))
|
||||
}
|
||||
}
|
||||
|
||||
/// Same as [`json_patch::merge`] but doesn't delete the key when the patch's value is `null`
|
||||
fn merge_patches(doc: &mut serde_json::Value, patch: &serde_json::Value) {
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
if !patch.is_object() {
|
||||
*doc = patch.clone();
|
||||
return;
|
||||
}
|
||||
|
||||
if !doc.is_object() {
|
||||
*doc = Value::Object(Map::new());
|
||||
}
|
||||
let map = doc.as_object_mut().unwrap();
|
||||
for (key, value) in patch.as_object().unwrap() {
|
||||
merge_patches(map.entry(key.as_str()).or_insert(Value::Null), value);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn merge_patches() {
|
||||
let mut json = serde_json::Value::Object(Default::default());
|
||||
|
||||
super::merge_patches(
|
||||
&mut json,
|
||||
&serde_json::json!({
|
||||
"app": {
|
||||
"withGlobalTauri": true,
|
||||
"windows": []
|
||||
},
|
||||
"plugins": {
|
||||
"test": "tauri"
|
||||
},
|
||||
"build": {
|
||||
"devUrl": "http://localhost:8080"
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
super::merge_patches(
|
||||
&mut json,
|
||||
&serde_json::json!({
|
||||
"app": { "withGlobalTauri": null }
|
||||
}),
|
||||
);
|
||||
|
||||
super::merge_patches(
|
||||
&mut json,
|
||||
&serde_json::json!({
|
||||
"app": { "windows": null }
|
||||
}),
|
||||
);
|
||||
|
||||
super::merge_patches(
|
||||
&mut json,
|
||||
&serde_json::json!({
|
||||
"plugins": { "updater": {
|
||||
"endpoints": ["https://tauri.app"]
|
||||
} }
|
||||
}),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
json,
|
||||
serde_json::json!({
|
||||
"app": {
|
||||
"withGlobalTauri": null,
|
||||
"windows": null
|
||||
},
|
||||
"plugins": {
|
||||
"test": "tauri",
|
||||
"updater": {
|
||||
"endpoints": ["https://tauri.app"]
|
||||
}
|
||||
},
|
||||
"build": {
|
||||
"devUrl": "http://localhost:8080"
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,15 +327,11 @@ mod sys {
|
||||
}
|
||||
|
||||
pub(super) fn error_contended(err: &Error) -> bool {
|
||||
err
|
||||
.raw_os_error()
|
||||
.map_or(false, |x| x == ERROR_LOCK_VIOLATION as i32)
|
||||
err.raw_os_error() == Some(ERROR_LOCK_VIOLATION as i32)
|
||||
}
|
||||
|
||||
pub(super) fn error_unsupported(err: &Error) -> bool {
|
||||
err
|
||||
.raw_os_error()
|
||||
.map_or(false, |x| x == ERROR_INVALID_FUNCTION as i32)
|
||||
err.raw_os_error() == Some(ERROR_INVALID_FUNCTION as i32)
|
||||
}
|
||||
|
||||
pub(super) fn unlock(file: &File) -> Result<()> {
|
||||
|
||||
@@ -119,3 +119,23 @@ pub fn run_hook(
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn strip_semver_prerelease_tag(version: &mut semver::Version) -> crate::Result<()> {
|
||||
if !version.pre.is_empty() {
|
||||
if let Some((_prerelease_tag, number)) = version.pre.as_str().to_string().split_once('.') {
|
||||
version.pre = semver::Prerelease::EMPTY;
|
||||
version.build = semver::BuildMetadata::new(&format!(
|
||||
"{prefix}{number}",
|
||||
prefix = if version.build.is_empty() {
|
||||
"".to_string()
|
||||
} else {
|
||||
format!(".{}", version.build.as_str())
|
||||
}
|
||||
))
|
||||
.with_context(|| format!("bundle version {number:?} prerelease is invalid"))?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -23,6 +23,17 @@ pub fn manager_version(package_manager: &str) -> Option<String> {
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn detect_yarn_or_berry() -> PackageManager {
|
||||
if manager_version("yarn")
|
||||
.map(|v| v.chars().next().map(|c| c > '1').unwrap_or_default())
|
||||
.unwrap_or(false)
|
||||
{
|
||||
PackageManager::YarnBerry
|
||||
} else {
|
||||
PackageManager::Yarn
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum PackageManager {
|
||||
Npm,
|
||||
@@ -59,32 +70,38 @@ impl PackageManager {
|
||||
.unwrap_or(Self::Npm)
|
||||
}
|
||||
|
||||
/// Detects package manager from the `npm_config_user_agent` environment variable
|
||||
fn from_environment_variable() -> Option<Self> {
|
||||
let npm_config_user_agent = std::env::var("npm_config_user_agent").ok()?;
|
||||
match npm_config_user_agent {
|
||||
user_agent if user_agent.starts_with("pnpm/") => Some(Self::Pnpm),
|
||||
user_agent if user_agent.starts_with("deno/") => Some(Self::Deno),
|
||||
user_agent if user_agent.starts_with("bun/") => Some(Self::Bun),
|
||||
user_agent if user_agent.starts_with("yarn/") => Some(detect_yarn_or_berry()),
|
||||
user_agent if user_agent.starts_with("npm/") => Some(Self::Npm),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Detects all possible package managers from the given directory.
|
||||
pub fn all_from_project<P: AsRef<Path>>(path: P) -> Vec<Self> {
|
||||
if let Some(from_env) = Self::from_environment_variable() {
|
||||
return vec![from_env];
|
||||
}
|
||||
|
||||
let mut found = Vec::new();
|
||||
|
||||
if let Ok(entries) = std::fs::read_dir(path) {
|
||||
for entry in entries.flatten() {
|
||||
let path = entry.path();
|
||||
let name = path.file_name().unwrap().to_string_lossy();
|
||||
if name.as_ref() == "package-lock.json" {
|
||||
found.push(PackageManager::Npm);
|
||||
} else if name.as_ref() == "pnpm-lock.yaml" {
|
||||
found.push(PackageManager::Pnpm);
|
||||
} else if name.as_ref() == "yarn.lock" {
|
||||
let yarn = if manager_version("yarn")
|
||||
.map(|v| v.chars().next().map(|c| c > '1').unwrap_or_default())
|
||||
.unwrap_or(false)
|
||||
{
|
||||
PackageManager::YarnBerry
|
||||
} else {
|
||||
PackageManager::Yarn
|
||||
};
|
||||
found.push(yarn);
|
||||
} else if name.as_ref() == "bun.lockb" {
|
||||
found.push(PackageManager::Bun);
|
||||
} else if name.as_ref() == "deno.lock" {
|
||||
found.push(PackageManager::Deno);
|
||||
match name.as_ref() {
|
||||
"package-lock.json" => found.push(PackageManager::Npm),
|
||||
"pnpm-lock.yaml" => found.push(PackageManager::Pnpm),
|
||||
"yarn.lock" => found.push(detect_yarn_or_berry()),
|
||||
"bun.lock" | "bun.lockb" => found.push(PackageManager::Bun),
|
||||
"deno.lock" => found.push(PackageManager::Deno),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +70,7 @@ pub fn known_plugins() -> HashMap<&'static str, PluginMetadata> {
|
||||
"upload",
|
||||
"websocket",
|
||||
"opener",
|
||||
"clipboard-manager",
|
||||
] {
|
||||
plugins.entry(p).or_default();
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ use tauri_utils::platform::Target;
|
||||
pub fn items(frontend_dir: Option<&PathBuf>, tauri_dir: Option<&Path>) -> Vec<SectionItem> {
|
||||
let mut items = Vec::new();
|
||||
if tauri_dir.is_some() {
|
||||
if let Ok(config) = crate::helpers::config::get(Target::current(), None) {
|
||||
if let Ok(config) = crate::helpers::config::get(Target::current(), &[]) {
|
||||
let config_guard = config.lock().unwrap();
|
||||
let config = config_guard.as_ref().unwrap();
|
||||
|
||||
|
||||
@@ -47,18 +47,20 @@ pub fn items(frontend_dir: Option<&PathBuf>, tauri_dir: Option<&Path>) -> Vec<Se
|
||||
if o.status.success() {
|
||||
let out = String::from_utf8_lossy(o.stdout.as_slice());
|
||||
let (package, version) = out.split_once(' ').unwrap_or_default();
|
||||
let latest_ver = crate_latest_version(package).unwrap_or_default();
|
||||
let version = version.strip_suffix('\n').unwrap_or(version);
|
||||
let latest_version = crate_latest_version(package).unwrap_or_default();
|
||||
format!(
|
||||
"{} {}: {}{}",
|
||||
package,
|
||||
"🦀",
|
||||
version.split_once('\n').unwrap_or_default().0,
|
||||
if !(version.is_empty() || latest_ver.is_empty()) {
|
||||
let version = semver::Version::parse(version).unwrap();
|
||||
let target_version = semver::Version::parse(latest_ver.as_str()).unwrap();
|
||||
"{package} 🦀: {version}{}",
|
||||
if !(version.is_empty() || latest_version.is_empty()) {
|
||||
let current_version = semver::Version::parse(version).unwrap();
|
||||
let target_version = semver::Version::parse(latest_version.as_str()).unwrap();
|
||||
|
||||
if version < target_version {
|
||||
format!(" ({}, latest: {})", "outdated".yellow(), latest_ver.green())
|
||||
if current_version < target_version {
|
||||
format!(
|
||||
" ({}, latest: {})",
|
||||
"outdated".yellow(),
|
||||
latest_version.green()
|
||||
)
|
||||
} else {
|
||||
"".into()
|
||||
}
|
||||
@@ -106,7 +108,6 @@ pub fn rust_section_item(dep: &str, crate_version: CrateVersion) -> SectionItem
|
||||
"🦀",
|
||||
crate_version,
|
||||
version_suffix
|
||||
.clone()
|
||||
.map(|s| format!(",{s}"))
|
||||
.unwrap_or_else(|| "".into())
|
||||
))
|
||||
|
||||
@@ -31,7 +31,7 @@ fn wix_upgrade_code() -> Result<()> {
|
||||
crate::helpers::app_paths::resolve();
|
||||
|
||||
let target = tauri_utils::platform::Target::Windows;
|
||||
let config = crate::helpers::config::get(target, None)?;
|
||||
let config = crate::helpers::config::get(target, &[])?;
|
||||
|
||||
let interface = AppInterface::new(config.lock().unwrap().as_ref().unwrap(), None)?;
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ pub trait AppSettings {
|
||||
enabled_features.push("default".into());
|
||||
}
|
||||
|
||||
let target: String = if let Some(target) = options.target.clone() {
|
||||
let target: String = if let Some(target) = options.target {
|
||||
target
|
||||
} else {
|
||||
tauri_utils::platform::target_triple()?
|
||||
|
||||
@@ -22,7 +22,8 @@ use notify_debouncer_full::new_debouncer;
|
||||
use serde::{Deserialize, Deserializer};
|
||||
use tauri_bundler::{
|
||||
AppCategory, AppImageSettings, BundleBinary, BundleSettings, DebianSettings, DmgSettings,
|
||||
MacOsSettings, PackageSettings, Position, RpmSettings, Size, UpdaterSettings, WindowsSettings,
|
||||
IosSettings, MacOsSettings, PackageSettings, Position, RpmSettings, Size, UpdaterSettings,
|
||||
WindowsSettings,
|
||||
};
|
||||
use tauri_utils::config::{parse::is_configuration_file, DeepLinkProtocol, Updater};
|
||||
|
||||
@@ -51,7 +52,7 @@ pub struct Options {
|
||||
pub target: Option<String>,
|
||||
pub features: Option<Vec<String>>,
|
||||
pub args: Vec<String>,
|
||||
pub config: Option<ConfigValue>,
|
||||
pub config: Vec<ConfigValue>,
|
||||
pub no_watch: bool,
|
||||
}
|
||||
|
||||
@@ -101,7 +102,7 @@ pub struct MobileOptions {
|
||||
pub debug: bool,
|
||||
pub features: Option<Vec<String>>,
|
||||
pub args: Vec<String>,
|
||||
pub config: Option<ConfigValue>,
|
||||
pub config: Vec<ConfigValue>,
|
||||
pub no_watch: bool,
|
||||
}
|
||||
|
||||
@@ -207,14 +208,14 @@ impl Interface for Rust {
|
||||
rx.recv().unwrap();
|
||||
Ok(())
|
||||
} else {
|
||||
let config = options.config.clone().map(|c| c.0);
|
||||
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(config, run)
|
||||
self.run_dev_watcher(&merge_configs, run)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,9 +237,9 @@ impl Interface for Rust {
|
||||
runner(options)?;
|
||||
Ok(())
|
||||
} else {
|
||||
let config = options.config.clone().map(|c| c.0);
|
||||
let merge_configs = options.config.iter().map(|c| &c.0).collect::<Vec<_>>();
|
||||
let run = Arc::new(|_rust: &mut Rust| runner(options.clone()));
|
||||
self.run_dev_watcher(config, run)
|
||||
self.run_dev_watcher(&merge_configs, run)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,35 +361,6 @@ fn lookup<F: FnMut(FileType, PathBuf)>(dir: &Path, mut f: F) {
|
||||
}
|
||||
}
|
||||
|
||||
fn shared_options(
|
||||
desktop_dev: bool,
|
||||
mobile: bool,
|
||||
args: &mut Vec<String>,
|
||||
features: &mut Option<Vec<String>>,
|
||||
app_settings: &RustAppSettings,
|
||||
) {
|
||||
if mobile {
|
||||
args.push("--lib".into());
|
||||
features
|
||||
.get_or_insert(Vec::new())
|
||||
.push("tauri/rustls-tls".into());
|
||||
} else {
|
||||
if !desktop_dev {
|
||||
args.push("--bins".into());
|
||||
}
|
||||
let all_features = app_settings
|
||||
.manifest
|
||||
.lock()
|
||||
.unwrap()
|
||||
.all_enabled_features(if let Some(f) = features { f } else { &[] });
|
||||
if !all_features.contains(&"tauri/rustls-tls".into()) {
|
||||
features
|
||||
.get_or_insert(Vec::new())
|
||||
.push("tauri/native-tls".into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn dev_options(
|
||||
mobile: bool,
|
||||
args: &mut Vec<String>,
|
||||
@@ -409,7 +381,9 @@ fn dev_options(
|
||||
}
|
||||
*args = dev_args;
|
||||
|
||||
shared_options(true, mobile, args, features, app_settings);
|
||||
if mobile {
|
||||
args.push("--lib".into());
|
||||
}
|
||||
|
||||
if !args.contains(&"--no-default-features".into()) {
|
||||
let manifest_features = app_settings.manifest.lock().unwrap().features();
|
||||
@@ -489,7 +463,11 @@ impl Rust {
|
||||
features
|
||||
.get_or_insert(Vec::new())
|
||||
.push("tauri/custom-protocol".into());
|
||||
shared_options(false, mobile, args, features, &self.app_settings);
|
||||
if mobile {
|
||||
args.push("--lib".into());
|
||||
} else {
|
||||
args.push("--bins".into());
|
||||
}
|
||||
}
|
||||
|
||||
fn run_dev<F: Fn(Option<i32>, ExitReason) + Send + Sync + 'static>(
|
||||
@@ -510,7 +488,7 @@ impl Rust {
|
||||
|
||||
fn run_dev_watcher<F: Fn(&mut Rust) -> crate::Result<Box<dyn DevProcess + Send>>>(
|
||||
&mut self,
|
||||
config: Option<serde_json::Value>,
|
||||
merge_configs: &[&serde_json::Value],
|
||||
run: Arc<F>,
|
||||
) -> crate::Result<()> {
|
||||
let child = run(self)?;
|
||||
@@ -560,7 +538,7 @@ 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, event_path) {
|
||||
if let Ok(config) = reload_config(config.as_ref()) {
|
||||
if let Ok(config) = reload_config(merge_configs) {
|
||||
let (manifest, modified) =
|
||||
rewrite_manifest(config.lock().unwrap().as_ref().unwrap())?;
|
||||
if modified {
|
||||
@@ -721,9 +699,7 @@ impl CargoSettings {
|
||||
toml_file
|
||||
.read_to_string(&mut toml_str)
|
||||
.with_context(|| "failed to read Cargo.toml")?;
|
||||
toml::from_str(&toml_str)
|
||||
.with_context(|| "failed to parse Cargo.toml")
|
||||
.map_err(Into::into)
|
||||
toml::from_str(&toml_str).with_context(|| "failed to parse Cargo.toml")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -819,8 +795,9 @@ impl AppSettings for RustAppSettings {
|
||||
config: &Config,
|
||||
features: &[String],
|
||||
) -> crate::Result<BundleSettings> {
|
||||
let arch64bits =
|
||||
self.target_triple.starts_with("x86_64") || self.target_triple.starts_with("aarch64");
|
||||
let arch64bits = self.target_triple.starts_with("x86_64")
|
||||
|| self.target_triple.starts_with("aarch64")
|
||||
|| self.target_triple.starts_with("riscv64");
|
||||
|
||||
let updater_enabled = config.bundle.create_updater_artifacts != Updater::Bool(false);
|
||||
let v1_compatible = matches!(config.bundle.create_updater_artifacts, Updater::String(_));
|
||||
@@ -859,7 +836,7 @@ impl AppSettings for RustAppSettings {
|
||||
.get("deep-link")
|
||||
.and_then(|c| c.get("desktop").cloned())
|
||||
{
|
||||
let protocols: DesktopDeepLinks = serde_json::from_value(plugin_config.clone())?;
|
||||
let protocols: DesktopDeepLinks = serde_json::from_value(plugin_config)?;
|
||||
settings.deep_link_protocols = Some(match protocols {
|
||||
DesktopDeepLinks::One(p) => vec![p],
|
||||
DesktopDeepLinks::List(p) => p,
|
||||
@@ -1040,24 +1017,26 @@ impl RustAppSettings {
|
||||
.workspace
|
||||
.and_then(|v| v.package);
|
||||
|
||||
let version = config.version.clone().unwrap_or_else(|| {
|
||||
cargo_package_settings
|
||||
.version
|
||||
.clone()
|
||||
.expect("Cargo manifest must have the `package.version` field")
|
||||
.resolve("version", || {
|
||||
ws_package_settings
|
||||
.as_ref()
|
||||
.and_then(|p| p.version.clone())
|
||||
.ok_or_else(|| anyhow::anyhow!("Couldn't inherit value for `version` from workspace"))
|
||||
})
|
||||
.expect("Cargo project does not have a version")
|
||||
});
|
||||
|
||||
let package_settings = PackageSettings {
|
||||
product_name: config
|
||||
.product_name
|
||||
.clone()
|
||||
.unwrap_or_else(|| cargo_package_settings.name.clone()),
|
||||
version: config.version.clone().unwrap_or_else(|| {
|
||||
cargo_package_settings
|
||||
.version
|
||||
.clone()
|
||||
.expect("Cargo manifest must have the `package.version` field")
|
||||
.resolve("version", || {
|
||||
ws_package_settings
|
||||
.as_ref()
|
||||
.and_then(|p| p.version.clone())
|
||||
.ok_or_else(|| anyhow::anyhow!("Couldn't inherit value for `version` from workspace"))
|
||||
})
|
||||
.expect("Cargo project does not have a version")
|
||||
}),
|
||||
version,
|
||||
description: cargo_package_settings
|
||||
.description
|
||||
.clone()
|
||||
@@ -1169,22 +1148,29 @@ pub(crate) fn get_cargo_metadata() -> crate::Result<CargoMetadata> {
|
||||
Ok(serde_json::from_slice(&output.stdout)?)
|
||||
}
|
||||
|
||||
/// 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> {
|
||||
let path = if let Some(target) = get_cargo_option(args, "--target-dir") {
|
||||
std::env::current_dir()?.join(target)
|
||||
} else {
|
||||
get_cargo_metadata()
|
||||
.with_context(|| "failed to get cargo metadata")?
|
||||
.target_directory
|
||||
};
|
||||
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
/// 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 = if let Some(target) = get_cargo_option(&options.args, "--target-dir") {
|
||||
std::env::current_dir()?.join(target)
|
||||
} else {
|
||||
let mut path = get_cargo_metadata()
|
||||
.with_context(|| "failed to get cargo metadata")?
|
||||
.target_directory;
|
||||
let mut path = get_cargo_target_dir(&options.args)?;
|
||||
|
||||
if let Some(triple) = triple {
|
||||
path.push(triple);
|
||||
}
|
||||
|
||||
path
|
||||
};
|
||||
if let Some(triple) = triple {
|
||||
path.push(triple);
|
||||
}
|
||||
|
||||
path.push(get_profile_dir(options));
|
||||
|
||||
@@ -1442,9 +1428,13 @@ fn tauri_config_to_bundle_settings(
|
||||
y: config.macos.dmg.application_folder_position.y,
|
||||
},
|
||||
},
|
||||
ios: IosSettings {
|
||||
bundle_version: config.ios.bundle_version,
|
||||
},
|
||||
macos: MacOsSettings {
|
||||
frameworks: config.macos.frameworks,
|
||||
files: config.macos.files,
|
||||
bundle_version: config.macos.bundle_version,
|
||||
minimum_system_version: config.macos.minimum_system_version,
|
||||
exception_domain: config.macos.exception_domain,
|
||||
signing_identity,
|
||||
@@ -1650,7 +1640,10 @@ mod tests {
|
||||
);
|
||||
assert_eq!(
|
||||
get_target_dir(Some("x86_64-pc-windows-msvc"), &options).unwrap(),
|
||||
current_dir.join("path/to/some/dir/release")
|
||||
current_dir
|
||||
.join("path/to/some/dir")
|
||||
.join("x86_64-pc-windows-msvc")
|
||||
.join("release")
|
||||
);
|
||||
|
||||
let options = Options {
|
||||
|
||||
@@ -81,6 +81,8 @@ pub fn run_dev<F: Fn(Option<i32>, ExitReason) + Send + Sync + 'static>(
|
||||
let manually_killed_app = Arc::new(AtomicBool::default());
|
||||
let manually_killed_app_ = manually_killed_app.clone();
|
||||
|
||||
log::info!(action = "Running"; "DevCommand (`{} {}`)", &dev_cmd.get_program().to_string_lossy(), dev_cmd.get_args().map(|arg| arg.to_string_lossy()).fold(String::new(), |acc, arg| format!("{acc} {arg}")));
|
||||
|
||||
let dev_child = match SharedChild::spawn(&mut dev_cmd) {
|
||||
Ok(c) => Ok(c),
|
||||
Err(e) if e.kind() == ErrorKind::NotFound => Err(anyhow::anyhow!(
|
||||
|
||||
@@ -63,10 +63,22 @@ impl FromStr for ConfigValue {
|
||||
} else {
|
||||
let path = PathBuf::from(config);
|
||||
if path.exists() {
|
||||
Ok(Self(serde_json::from_str(
|
||||
&read_to_string(&path)
|
||||
.with_context(|| format!("invalid configuration at file {config}"))?,
|
||||
)?))
|
||||
let raw = &read_to_string(&path)
|
||||
.with_context(|| format!("invalid configuration at file {config}"))?;
|
||||
match path.extension() {
|
||||
Some(ext) if ext == "toml" => Ok(Self(::toml::from_str(raw)?)),
|
||||
Some(ext) if ext == "json5" => Ok(Self(::json5::from_str(raw)?)),
|
||||
// treat all other extensions as json
|
||||
_ => Ok(Self(
|
||||
// from tauri-utils/src/config/parse.rs:
|
||||
// we also want to support **valid** json5 in the .json extension
|
||||
// if the json5 is not valid the serde_json error for regular json will be returned.
|
||||
match ::json5::from_str(raw) {
|
||||
Ok(json5) => json5,
|
||||
Err(_) => serde_json::from_str(raw)?,
|
||||
},
|
||||
)),
|
||||
}
|
||||
} else {
|
||||
anyhow::bail!("provided configuration path does not exist")
|
||||
}
|
||||
@@ -235,13 +247,13 @@ where
|
||||
if !is_command_output {
|
||||
let style = Style::new().fg_color(Some(AnsiColor::Green.into())).bold();
|
||||
|
||||
write!(f, " {style}{}{style:#} ", action)?;
|
||||
write!(f, "{style}{action:>12}{style:#} ")?;
|
||||
}
|
||||
} else {
|
||||
let style = f.default_level_style(record.level()).bold();
|
||||
write!(
|
||||
f,
|
||||
" {style}{}{style:#} ",
|
||||
"{style}{:>12}{style:#} ",
|
||||
prettyprint_level(record.level())
|
||||
)?;
|
||||
}
|
||||
@@ -319,7 +331,7 @@ impl CommandExt for Command {
|
||||
let program = self.get_program().to_string_lossy().into_owned();
|
||||
log::debug!(action = "Running"; "Command `{} {}`", program, self.get_args().map(|arg| arg.to_string_lossy()).fold(String::new(), |acc, arg| format!("{acc} {arg}")));
|
||||
|
||||
self.status().map_err(Into::into)
|
||||
self.status()
|
||||
}
|
||||
|
||||
fn output_ok(&mut self) -> crate::Result<Output> {
|
||||
|
||||
@@ -535,13 +535,13 @@ function App() {
|
||||
<h1>Welcome to Tauri!</h1>
|
||||
|
||||
<div className="row">
|
||||
<a href="https://vitejs.dev" target="_blank">
|
||||
<a href="https://vite.dev" target="_blank">
|
||||
<img src="/vite.svg" className="logo vite" alt="Vite logo" />
|
||||
</a>
|
||||
<a href="https://tauri.app" target="_blank">
|
||||
<img src="/tauri.svg" className="logo tauri" alt="Tauri logo" />
|
||||
</a>
|
||||
<a href="https://reactjs.org" target="_blank">
|
||||
<a href="https://react.dev" target="_blank">
|
||||
<img src={reactLogo} className="logo react" alt="React logo" />
|
||||
</a>
|
||||
</div>
|
||||
@@ -609,13 +609,13 @@ function App() {
|
||||
<h1>Welcome to Tauri!</h1>
|
||||
|
||||
<div className="row">
|
||||
<a href="https://vitejs.dev" target="_blank">
|
||||
<a href="https://vite.dev" target="_blank">
|
||||
<img src="/vite.svg" className="logo vite" alt="Vite logo" />
|
||||
</a>
|
||||
<a href="https://tauri.app" target="_blank">
|
||||
<img src="/tauri.svg" className="logo tauri" alt="Tauri logo" />
|
||||
</a>
|
||||
<a href="https://reactjs.org" target="_blank">
|
||||
<a href="https://react.dev" target="_blank">
|
||||
<img src={reactLogo} className="logo react" alt="React logo" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -31,7 +31,7 @@ impl<'a> SveltePartialLoader<'a> {
|
||||
let mut pointer = 0;
|
||||
|
||||
// find opening "<script"
|
||||
let offset = script_start_finder.find(self.source_text[pointer..].as_bytes())?;
|
||||
let offset = script_start_finder.find(&self.source_text.as_bytes()[pointer..])?;
|
||||
pointer += offset + SCRIPT_START.len();
|
||||
|
||||
// find closing ">"
|
||||
@@ -45,7 +45,7 @@ impl<'a> SveltePartialLoader<'a> {
|
||||
let js_start = pointer;
|
||||
|
||||
// find "</script>"
|
||||
let offset = script_end_finder.find(self.source_text[pointer..].as_bytes())?;
|
||||
let offset = script_end_finder.find(&self.source_text.as_bytes()[pointer..])?;
|
||||
let js_end = pointer + offset;
|
||||
|
||||
let source_text = &self.source_text[js_start..js_end];
|
||||
|
||||
@@ -25,7 +25,7 @@ impl<'a> VuePartialLoader<'a> {
|
||||
/// Each *.vue file can contain at most
|
||||
/// * one `<script>` block (excluding `<script setup>`).
|
||||
/// * one `<script setup>` block (excluding normal `<script>`).
|
||||
/// <https://vuejs.org/api/sfc-spec.html#script>
|
||||
/// <https://vuejs.org/api/sfc-spec.html#script>
|
||||
fn parse_scripts(&self) -> Vec<JavaScriptSource<'a>> {
|
||||
let mut pointer = 0;
|
||||
let Some(result1) = self.parse_script(&mut pointer) else {
|
||||
@@ -42,7 +42,7 @@ impl<'a> VuePartialLoader<'a> {
|
||||
let script_end_finder = Finder::new(SCRIPT_END);
|
||||
|
||||
// find opening "<script"
|
||||
let offset = script_start_finder.find(self.source_text[*pointer..].as_bytes())?;
|
||||
let offset = script_start_finder.find(&self.source_text.as_bytes()[*pointer..])?;
|
||||
*pointer += offset + SCRIPT_START.len();
|
||||
|
||||
// find closing ">"
|
||||
@@ -57,7 +57,7 @@ impl<'a> VuePartialLoader<'a> {
|
||||
let js_start = *pointer;
|
||||
|
||||
// find "</script>"
|
||||
let offset = script_end_finder.find(self.source_text[*pointer..].as_bytes())?;
|
||||
let offset = script_end_finder.find(&self.source_text.as_bytes()[*pointer..])?;
|
||||
let js_end = *pointer + offset;
|
||||
*pointer += offset + SCRIPT_END.len();
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ pub fn command(options: Options) -> Result<()> {
|
||||
Profile::Debug
|
||||
};
|
||||
|
||||
let tauri_config = get_tauri_config(tauri_utils::platform::Target::Android, None)?;
|
||||
let tauri_config = get_tauri_config(tauri_utils::platform::Target::Android, &[])?;
|
||||
|
||||
let (config, metadata, cli_options) = {
|
||||
let tauri_config_guard = tauri_config.lock().unwrap();
|
||||
@@ -72,8 +72,14 @@ pub fn command(options: Options) -> Result<()> {
|
||||
MobileTarget::Android,
|
||||
)?;
|
||||
|
||||
if let Some(config) = &cli_options.config {
|
||||
crate::helpers::config::merge_with(&config.0)?;
|
||||
if !cli_options.config.is_empty() {
|
||||
crate::helpers::config::merge_with(
|
||||
&cli_options
|
||||
.config
|
||||
.iter()
|
||||
.map(|conf| &conf.0)
|
||||
.collect::<Vec<_>>(),
|
||||
)?;
|
||||
}
|
||||
|
||||
let env = env()?;
|
||||
|
||||
@@ -49,9 +49,15 @@ pub struct Options {
|
||||
/// List of cargo features to activate
|
||||
#[clap(short, long, action = ArgAction::Append, num_args(0..))]
|
||||
pub features: Option<Vec<String>>,
|
||||
/// JSON string or path to JSON file to merge with tauri.conf.json
|
||||
/// 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.
|
||||
///
|
||||
/// Note that a platform-specific file is looked up and merged with the default file by default
|
||||
/// (tauri.macos.conf.json, tauri.linux.conf.json, tauri.windows.conf.json, tauri.android.conf.json and tauri.ios.conf.json)
|
||||
/// but you can use this for more specific use cases such as different build flavors.
|
||||
#[clap(short, long)]
|
||||
pub config: Option<ConfigValue>,
|
||||
pub config: Vec<ConfigValue>,
|
||||
/// Whether to split the APKs and AABs per ABIs.
|
||||
#[clap(long)]
|
||||
pub split_per_abi: bool,
|
||||
@@ -105,7 +111,11 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> {
|
||||
|
||||
let tauri_config = get_tauri_config(
|
||||
tauri_utils::platform::Target::Android,
|
||||
options.config.as_ref().map(|c| &c.0),
|
||||
&options
|
||||
.config
|
||||
.iter()
|
||||
.map(|conf| &conf.0)
|
||||
.collect::<Vec<_>>(),
|
||||
)?;
|
||||
let (interface, config, metadata) = {
|
||||
let tauri_config_guard = tauri_config.lock().unwrap();
|
||||
@@ -200,7 +210,7 @@ fn run_build(
|
||||
args: build_options.args.clone(),
|
||||
noise_level,
|
||||
vars: Default::default(),
|
||||
config: build_options.config.clone(),
|
||||
config: build_options.config,
|
||||
target_device: None,
|
||||
};
|
||||
let handle = write_options(
|
||||
|
||||
@@ -48,9 +48,15 @@ pub struct Options {
|
||||
/// Exit on panic
|
||||
#[clap(short, long)]
|
||||
exit_on_panic: bool,
|
||||
/// JSON string or path to JSON file to merge with tauri.conf.json
|
||||
/// 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.
|
||||
///
|
||||
/// Note that a platform-specific file is looked up and merged with the default file by default
|
||||
/// (tauri.macos.conf.json, tauri.linux.conf.json, tauri.windows.conf.json, tauri.android.conf.json and tauri.ios.conf.json)
|
||||
/// but you can use this for more specific use cases such as different build flavors.
|
||||
#[clap(short, long)]
|
||||
pub config: Option<ConfigValue>,
|
||||
pub config: Vec<ConfigValue>,
|
||||
/// Run the code in release mode
|
||||
#[clap(long = "release")]
|
||||
pub release_mode: bool,
|
||||
@@ -126,7 +132,11 @@ fn run_command(options: Options, noise_level: NoiseLevel) -> Result<()> {
|
||||
|
||||
let tauri_config = get_tauri_config(
|
||||
tauri_utils::platform::Target::Android,
|
||||
options.config.as_ref().map(|c| &c.0),
|
||||
&options
|
||||
.config
|
||||
.iter()
|
||||
.map(|conf| &conf.0)
|
||||
.collect::<Vec<_>>(),
|
||||
)?;
|
||||
|
||||
let env = env()?;
|
||||
@@ -147,7 +157,7 @@ fn run_command(options: Options, noise_level: NoiseLevel) -> Result<()> {
|
||||
.as_ref()
|
||||
.map(|d| d.target().triple.to_string())
|
||||
.unwrap_or_else(|| Target::all().values().next().unwrap().triple.into());
|
||||
dev_options.target = Some(target_triple.clone());
|
||||
dev_options.target = Some(target_triple);
|
||||
|
||||
let (interface, config, metadata) = {
|
||||
let tauri_config_guard = tauri_config.lock().unwrap();
|
||||
|
||||
@@ -43,7 +43,7 @@ pub fn exec(
|
||||
#[allow(unused_variables)] reinstall_deps: bool,
|
||||
skip_targets_install: bool,
|
||||
) -> Result<App> {
|
||||
let tauri_config = get_tauri_config(target.platform_target(), None)?;
|
||||
let tauri_config = get_tauri_config(target.platform_target(), &[])?;
|
||||
|
||||
let tauri_config_guard = tauri_config.lock().unwrap();
|
||||
let tauri_config_ = tauri_config_guard.as_ref().unwrap();
|
||||
@@ -142,7 +142,7 @@ 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_, None, &Default::default())?;
|
||||
map.insert("apple", &config);
|
||||
super::ios::project::gen(
|
||||
tauri_config_,
|
||||
|
||||
@@ -14,7 +14,7 @@ use crate::{
|
||||
config::{get as get_tauri_config, ConfigHandle},
|
||||
flock,
|
||||
},
|
||||
interface::{AppInterface, AppSettings, Interface, Options as InterfaceOptions},
|
||||
interface::{AppInterface, Interface, Options as InterfaceOptions},
|
||||
mobile::{write_options, CliOptions},
|
||||
ConfigValue, Result,
|
||||
};
|
||||
@@ -60,9 +60,15 @@ pub struct Options {
|
||||
/// List of cargo features to activate
|
||||
#[clap(short, long, action = ArgAction::Append, num_args(0..))]
|
||||
pub features: Option<Vec<String>>,
|
||||
/// JSON string or path to JSON file to merge with tauri.conf.json
|
||||
/// 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.
|
||||
///
|
||||
/// Note that a platform-specific file is looked up and merged with the default file by default
|
||||
/// (tauri.macos.conf.json, tauri.linux.conf.json, tauri.windows.conf.json, tauri.android.conf.json and tauri.ios.conf.json)
|
||||
/// but you can use this for more specific use cases such as different build flavors.
|
||||
#[clap(short, long)]
|
||||
pub config: Option<ConfigValue>,
|
||||
pub config: Vec<ConfigValue>,
|
||||
/// Build number to append to the app version.
|
||||
#[clap(long)]
|
||||
pub build_number: Option<u32>,
|
||||
@@ -145,7 +151,7 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> {
|
||||
|
||||
let tauri_config = get_tauri_config(
|
||||
tauri_utils::platform::Target::Ios,
|
||||
options.config.as_ref().map(|c| &c.0),
|
||||
&options.config.iter().map(|c| &c.0).collect::<Vec<_>>(),
|
||||
)?;
|
||||
let (interface, mut config) = {
|
||||
let tauri_config_guard = tauri_config.lock().unwrap();
|
||||
@@ -160,7 +166,7 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> {
|
||||
tauri_config_,
|
||||
build_options.features.as_ref(),
|
||||
&Default::default(),
|
||||
);
|
||||
)?;
|
||||
(interface, config)
|
||||
};
|
||||
|
||||
@@ -176,9 +182,10 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> {
|
||||
inject_resources(&config, tauri_config.lock().unwrap().as_ref().unwrap())?;
|
||||
|
||||
let mut plist = plist::Dictionary::new();
|
||||
let version = interface.app_settings().get_package_settings().version;
|
||||
plist.insert("CFBundleShortVersionString".into(), version.clone().into());
|
||||
plist.insert("CFBundleVersion".into(), version.into());
|
||||
plist.insert(
|
||||
"CFBundleShortVersionString".into(),
|
||||
config.bundle_version_short().into(),
|
||||
);
|
||||
|
||||
let info_plist_path = config
|
||||
.project_dir()
|
||||
@@ -293,6 +300,10 @@ fn run_build(
|
||||
cli_options,
|
||||
)?;
|
||||
|
||||
if options.open {
|
||||
return Ok(handle);
|
||||
}
|
||||
|
||||
let mut out_files = Vec::new();
|
||||
|
||||
call_for_targets_with_fallback(
|
||||
@@ -300,9 +311,10 @@ fn run_build(
|
||||
&detect_target_ok,
|
||||
env,
|
||||
|target: &Target| -> Result<()> {
|
||||
let mut app_version = config.bundle_version().clone();
|
||||
let mut app_version = config.bundle_version().to_string();
|
||||
if let Some(build_number) = options.build_number {
|
||||
app_version.push_extra(build_number);
|
||||
app_version.push('.');
|
||||
app_version.push_str(&build_number.to_string());
|
||||
}
|
||||
|
||||
let credentials = auth_credentials_from_env()?;
|
||||
@@ -315,7 +327,7 @@ fn run_build(
|
||||
.skip_codesign();
|
||||
}
|
||||
|
||||
target.build(config, env, noise_level, profile, build_config)?;
|
||||
target.build(None, config, env, noise_level, profile, build_config)?;
|
||||
|
||||
let mut archive_config = ArchiveConfig::new();
|
||||
if skip_signing {
|
||||
|
||||
@@ -25,7 +25,8 @@ use anyhow::Context;
|
||||
use cargo_mobile2::{
|
||||
apple::{
|
||||
config::Config as AppleConfig,
|
||||
device::{Device, DeviceKind},
|
||||
device::{Device, DeviceKind, RunError},
|
||||
target::BuildError,
|
||||
},
|
||||
env::Env,
|
||||
opts::{NoiseLevel, Profile},
|
||||
@@ -54,9 +55,15 @@ pub struct Options {
|
||||
/// Exit on panic
|
||||
#[clap(short, long)]
|
||||
exit_on_panic: bool,
|
||||
/// JSON string or path to JSON file to merge with tauri.conf.json
|
||||
/// 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.
|
||||
///
|
||||
/// Note that a platform-specific file is looked up and merged with the default file by default
|
||||
/// (tauri.macos.conf.json, tauri.linux.conf.json, tauri.windows.conf.json, tauri.android.conf.json and tauri.ios.conf.json)
|
||||
/// but you can use this for more specific use cases such as different build flavors.
|
||||
#[clap(short, long)]
|
||||
pub config: Option<ConfigValue>,
|
||||
pub config: Vec<ConfigValue>,
|
||||
/// Run the code in release mode
|
||||
#[clap(long = "release")]
|
||||
pub release_mode: bool,
|
||||
@@ -148,7 +155,7 @@ fn run_command(options: Options, noise_level: NoiseLevel) -> Result<()> {
|
||||
|
||||
let tauri_config = get_tauri_config(
|
||||
tauri_utils::platform::Target::Ios,
|
||||
options.config.as_ref().map(|c| &c.0),
|
||||
&options.config.iter().map(|c| &c.0).collect::<Vec<_>>(),
|
||||
)?;
|
||||
let (interface, config) = {
|
||||
let tauri_config_guard = tauri_config.lock().unwrap();
|
||||
@@ -162,7 +169,7 @@ fn run_command(options: Options, noise_level: NoiseLevel) -> Result<()> {
|
||||
tauri_config_,
|
||||
dev_options.features.as_ref(),
|
||||
&Default::default(),
|
||||
);
|
||||
)?;
|
||||
|
||||
(interface, config)
|
||||
};
|
||||
@@ -277,24 +284,29 @@ fn run_dev(
|
||||
cli_options,
|
||||
)?;
|
||||
|
||||
if open {
|
||||
let open_xcode = || {
|
||||
if !set_host {
|
||||
log::warn!("{PHYSICAL_IPHONE_DEV_WARNING}");
|
||||
}
|
||||
open_and_wait(config, &env)
|
||||
};
|
||||
|
||||
if open {
|
||||
open_xcode()
|
||||
} else if let Some(device) = &device {
|
||||
match run(device, options, config, noise_level, &env) {
|
||||
Ok(c) => Ok(Box::new(c) as Box<dyn DevProcess + Send>),
|
||||
Err(RunError::BuildFailed(BuildError::Sdk(sdk_err))) => {
|
||||
log::warn!("{sdk_err}");
|
||||
open_xcode()
|
||||
}
|
||||
Err(e) => {
|
||||
crate::dev::kill_before_dev_process();
|
||||
Err(e)
|
||||
Err(e.into())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if !set_host {
|
||||
log::warn!("{PHYSICAL_IPHONE_DEV_WARNING}");
|
||||
}
|
||||
open_and_wait(config, &env)
|
||||
open_xcode()
|
||||
}
|
||||
},
|
||||
)
|
||||
@@ -306,7 +318,7 @@ fn run(
|
||||
config: &AppleConfig,
|
||||
noise_level: NoiseLevel,
|
||||
env: &Env,
|
||||
) -> crate::Result<DevChild> {
|
||||
) -> std::result::Result<DevChild, RunError> {
|
||||
let profile = if options.debug {
|
||||
Profile::Debug
|
||||
} else {
|
||||
@@ -322,5 +334,4 @@ fn run(
|
||||
profile,
|
||||
)
|
||||
.map(DevChild::new)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ use crate::{
|
||||
helpers::{
|
||||
app_paths::tauri_dir,
|
||||
config::{BundleResources, Config as TauriConfig, ConfigHandle},
|
||||
pbxproj,
|
||||
pbxproj, strip_semver_prerelease_tag,
|
||||
},
|
||||
Result,
|
||||
};
|
||||
@@ -39,6 +39,7 @@ use std::{
|
||||
env::{set_var, var_os},
|
||||
fs::create_dir_all,
|
||||
path::PathBuf,
|
||||
str::FromStr,
|
||||
thread::sleep,
|
||||
time::Duration,
|
||||
};
|
||||
@@ -112,7 +113,7 @@ pub fn get_config(
|
||||
tauri_config: &TauriConfig,
|
||||
features: Option<&Vec<String>>,
|
||||
cli_options: &CliOptions,
|
||||
) -> (AppleConfig, AppleMetadata) {
|
||||
) -> Result<(AppleConfig, AppleMetadata)> {
|
||||
let mut ios_options = cli_options.clone();
|
||||
if let Some(features) = features {
|
||||
ios_options
|
||||
@@ -121,6 +122,83 @@ pub fn get_config(
|
||||
.extend_from_slice(features);
|
||||
}
|
||||
|
||||
let bundle_version = if let Some(bundle_version) = tauri_config
|
||||
.bundle
|
||||
.ios
|
||||
.bundle_version
|
||||
.clone()
|
||||
.or_else(|| tauri_config.version.clone())
|
||||
{
|
||||
// if it's a semver string, we must strip the prerelease tag
|
||||
if let Ok(mut version) = semver::Version::from_str(&bundle_version) {
|
||||
if !version.pre.is_empty() {
|
||||
log::warn!("CFBundleVersion cannot have prerelease tag; stripping from {bundle_version}");
|
||||
strip_semver_prerelease_tag(&mut version)?;
|
||||
}
|
||||
// correctly serialize version - cannot contain `+` as build metadata separator
|
||||
Some(format!(
|
||||
"{}.{}.{}{}",
|
||||
version.major,
|
||||
version.minor,
|
||||
version.patch,
|
||||
if version.build.is_empty() {
|
||||
"".to_string()
|
||||
} else {
|
||||
format!(".{}", version.build.as_str())
|
||||
}
|
||||
))
|
||||
} else {
|
||||
// let it go as is - cargo-mobile2 will validate it
|
||||
Some(bundle_version)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let full_bundle_version_short = if let Some(app_version) = &tauri_config.version {
|
||||
if let Ok(mut version) = semver::Version::from_str(app_version) {
|
||||
if !version.pre.is_empty() {
|
||||
log::warn!(
|
||||
"CFBundleShortVersionString cannot have prerelease tag; stripping from {app_version}"
|
||||
);
|
||||
strip_semver_prerelease_tag(&mut version)?;
|
||||
}
|
||||
// correctly serialize version - cannot contain `+` as build metadata separator
|
||||
Some(format!(
|
||||
"{}.{}.{}{}",
|
||||
version.major,
|
||||
version.minor,
|
||||
version.patch,
|
||||
if version.build.is_empty() {
|
||||
"".to_string()
|
||||
} else {
|
||||
format!(".{}", version.build.as_str())
|
||||
}
|
||||
))
|
||||
} else {
|
||||
// let it go as is - cargo-mobile2 will validate it
|
||||
Some(app_version.clone())
|
||||
}
|
||||
} else {
|
||||
bundle_version.clone()
|
||||
};
|
||||
let bundle_version_short = if let Some(full_version) = full_bundle_version_short.as_deref() {
|
||||
let mut s = full_version.split('.');
|
||||
let short_version = format!(
|
||||
"{}.{}.{}",
|
||||
s.next().unwrap_or("0"),
|
||||
s.next().unwrap_or("0"),
|
||||
s.next().unwrap_or("0")
|
||||
);
|
||||
|
||||
if short_version != full_version {
|
||||
log::warn!("{full_version:?} is not a valid CFBundleShortVersionString since it must contain exactly three dot separated integers; setting it to {short_version} instead");
|
||||
}
|
||||
|
||||
Some(short_version)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let raw = RawAppleConfig {
|
||||
development_team: std::env::var(APPLE_DEVELOPMENT_TEAM_ENV_VAR_NAME)
|
||||
.ok()
|
||||
@@ -140,12 +218,12 @@ pub fn get_config(
|
||||
}
|
||||
}),
|
||||
ios_features: ios_options.features.clone(),
|
||||
bundle_version: tauri_config.version.clone(),
|
||||
bundle_version_short: tauri_config.version.clone(),
|
||||
bundle_version,
|
||||
bundle_version_short,
|
||||
ios_version: Some(tauri_config.bundle.ios.minimum_system_version.clone()),
|
||||
..Default::default()
|
||||
};
|
||||
let config = AppleConfig::from_raw(app.clone(), Some(raw)).unwrap();
|
||||
let config = AppleConfig::from_raw(app.clone(), Some(raw))?;
|
||||
|
||||
let tauri_dir = tauri_dir();
|
||||
|
||||
@@ -194,7 +272,7 @@ pub fn get_config(
|
||||
set_var("TAURI_IOS_PROJECT_PATH", config.project_dir());
|
||||
set_var("TAURI_IOS_APP_NAME", config.app().name());
|
||||
|
||||
(config, metadata)
|
||||
Ok((config, metadata))
|
||||
}
|
||||
|
||||
fn connected_device_prompt<'a>(env: &'_ Env, target: Option<&str>) -> Result<Device<'a>> {
|
||||
|
||||
@@ -73,7 +73,7 @@ pub fn gen(
|
||||
let macos_pods = metadata.macos().pods().unwrap_or_default();
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
let default_archs = ["arm64", "arm64-sim"];
|
||||
let default_archs = ["arm64"];
|
||||
#[cfg(not(target_arch = "aarch64"))]
|
||||
let default_archs = ["arm64", "x86_64"];
|
||||
|
||||
|
||||
@@ -65,10 +65,14 @@ pub fn command(options: Options) -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
// `xcode-script` is ran from the `gen/apple` folder when not using NPM.
|
||||
// `xcode-script` is ran from the `gen/apple` folder when not using NPM/yarn/pnpm.
|
||||
// so we must change working directory to the src-tauri folder to resolve the tauri dir
|
||||
// additionally, bun@<1.2 does not modify the current working directory, so it is also runs this script from `gen/apple`
|
||||
// bun@>1.2 now actually moves the CWD to the package root so we shouldn't modify CWD in that case
|
||||
// see https://bun.sh/blog/bun-v1.2#bun-run-uses-the-correct-directory
|
||||
if (var_os("npm_lifecycle_event").is_none() && var_os("PNPM_PACKAGE_NAME").is_none())
|
||||
|| var("npm_config_user_agent").is_ok_and(|agent| agent.starts_with("bun"))
|
||||
|| var("npm_config_user_agent")
|
||||
.is_ok_and(|agent| agent.starts_with("bun/1.0") || agent.starts_with("bun/1.1"))
|
||||
{
|
||||
set_current_dir(current_dir()?.parent().unwrap().parent().unwrap()).unwrap();
|
||||
}
|
||||
@@ -78,7 +82,7 @@ pub fn command(options: Options) -> Result<()> {
|
||||
let profile = profile_from_configuration(&options.configuration);
|
||||
let macos = macos_from_platform(&options.platform);
|
||||
|
||||
let tauri_config = get_tauri_config(tauri_utils::platform::Target::Ios, None)?;
|
||||
let tauri_config = get_tauri_config(tauri_utils::platform::Target::Ios, &[])?;
|
||||
|
||||
let (config, metadata, cli_options) = {
|
||||
let tauri_config_guard = tauri_config.lock().unwrap();
|
||||
@@ -93,7 +97,7 @@ pub fn command(options: Options) -> Result<()> {
|
||||
tauri_config_,
|
||||
None,
|
||||
&cli_options,
|
||||
);
|
||||
)?;
|
||||
(config, metadata, cli_options)
|
||||
};
|
||||
ensure_init(
|
||||
@@ -103,8 +107,14 @@ pub fn command(options: Options) -> Result<()> {
|
||||
MobileTarget::Ios,
|
||||
)?;
|
||||
|
||||
if let Some(config) = &cli_options.config {
|
||||
crate::helpers::config::merge_with(&config.0)?;
|
||||
if !cli_options.config.is_empty() {
|
||||
crate::helpers::config::merge_with(
|
||||
&cli_options
|
||||
.config
|
||||
.iter()
|
||||
.map(|conf| &conf.0)
|
||||
.collect::<Vec<_>>(),
|
||||
)?;
|
||||
}
|
||||
|
||||
let env = env()?.explicit_env_vars(cli_options.vars);
|
||||
@@ -165,17 +175,24 @@ pub fn command(options: Options) -> Result<()> {
|
||||
|
||||
let isysroot = format!("-isysroot {}", options.sdk_root.display());
|
||||
|
||||
for arch in options.arches {
|
||||
let simulator = options.arches.contains(&"Simulator".to_string());
|
||||
let arches = if simulator {
|
||||
// when compiling for the simulator, we don't need to build other targets
|
||||
vec![if cfg!(target_arch = "aarch64") {
|
||||
"arm64"
|
||||
} else {
|
||||
"x86_64"
|
||||
}
|
||||
.to_string()]
|
||||
} else {
|
||||
options.arches
|
||||
};
|
||||
for arch in arches {
|
||||
// Set target-specific flags
|
||||
let (env_triple, rust_triple) = match arch.as_str() {
|
||||
"arm64" => ("aarch64_apple_ios", "aarch64-apple-ios"),
|
||||
"arm64-sim" => ("aarch64_apple_ios_sim", "aarch64-apple-ios-sim"),
|
||||
"arm64" if !simulator => ("aarch64_apple_ios", "aarch64-apple-ios"),
|
||||
"arm64" if simulator => ("aarch64_apple_ios_sim", "aarch64-apple-ios-sim"),
|
||||
"x86_64" => ("x86_64_apple_ios", "x86_64-apple-ios"),
|
||||
"Simulator" => {
|
||||
// when using Xcode, the arches for a simulator build will be ['Simulator', 'arm64-sim'] instead of ['arm64-sim']
|
||||
// so we ignore that on our end
|
||||
continue;
|
||||
}
|
||||
_ => {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Arch specified by Xcode was invalid. {} isn't a known arch",
|
||||
@@ -200,7 +217,12 @@ pub fn command(options: Options) -> Result<()> {
|
||||
let target = if macos {
|
||||
&macos_target
|
||||
} else {
|
||||
Target::for_arch(&arch).ok_or_else(|| {
|
||||
Target::for_arch(if arch == "arm64" && simulator {
|
||||
"arm64-sim"
|
||||
} else {
|
||||
&arch
|
||||
})
|
||||
.ok_or_else(|| {
|
||||
anyhow::anyhow!(
|
||||
"Arch specified by Xcode was invalid. {} isn't a known arch",
|
||||
arch
|
||||
|
||||
@@ -187,7 +187,7 @@ pub struct CliOptions {
|
||||
pub args: Vec<String>,
|
||||
pub noise_level: NoiseLevel,
|
||||
pub vars: HashMap<String, OsString>,
|
||||
pub config: Option<ConfigValue>,
|
||||
pub config: Vec<ConfigValue>,
|
||||
pub target_device: Option<TargetDevice>,
|
||||
}
|
||||
|
||||
@@ -199,7 +199,7 @@ impl Default for CliOptions {
|
||||
args: vec!["--lib".into()],
|
||||
noise_level: Default::default(),
|
||||
vars: Default::default(),
|
||||
config: None,
|
||||
config: Vec::new(),
|
||||
target_device: None,
|
||||
}
|
||||
}
|
||||
@@ -292,26 +292,21 @@ fn use_network_address_for_dev_url(
|
||||
url.path()
|
||||
))?;
|
||||
|
||||
if let Some(c) = &mut dev_options.config {
|
||||
if let Some(build) = c
|
||||
.0
|
||||
.as_object_mut()
|
||||
.and_then(|root| root.get_mut("build"))
|
||||
.and_then(|build| build.as_object_mut())
|
||||
{
|
||||
build.insert("devUrl".into(), url.to_string().into());
|
||||
}
|
||||
} else {
|
||||
let mut build = serde_json::Map::new();
|
||||
build.insert("devUrl".into(), url.to_string().into());
|
||||
dev_options
|
||||
.config
|
||||
.push(crate::ConfigValue(serde_json::json!({
|
||||
"build": {
|
||||
"devUrl": url
|
||||
}
|
||||
})));
|
||||
|
||||
dev_options
|
||||
reload_config(
|
||||
&dev_options
|
||||
.config
|
||||
.replace(crate::ConfigValue(serde_json::json!({
|
||||
"build": build
|
||||
})));
|
||||
}
|
||||
reload_config(dev_options.config.as_ref().map(|c| &c.0))?;
|
||||
.iter()
|
||||
.map(|conf| &conf.0)
|
||||
.collect::<Vec<_>>(),
|
||||
)?;
|
||||
|
||||
Some(ip)
|
||||
} else {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user