Compare commits

..

21 Commits

Author SHA1 Message Date
amrbashir
0fa69531ea Merge branch '1.x' into feat/cli/kill-dev-app-api 2024-02-10 02:35:55 +02:00
Fabian-Lars
510b62261c chore(core): Add missing changefile for #8546 (#8822) 2024-02-08 16:27:19 +02:00
Amr Bashir
b0f27814b9 fix(cli): map --profile dev to debug folder when finding executable (#8776) 2024-02-05 16:12:08 +02:00
John Smith
cc3d8e7731 fix(core): Command::output suspend while wait for response (#8539)
* fix: Command::output suspend while wait for response

* add change file

---------

Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
Co-authored-by: Lucas Fernandes Nogueira <lucas@tauri.app>
2024-02-01 08:06:05 -03:00
Amr Bashir
8ce51cec3b feat: retain cli args when relaunching after update, closes #7402 (#7718)
* feat: retain cli args when relaunching after update, closes #7402

* 1.61 compatible OsString join

* fix msi impl as well

* fix tests

* Update .changes/tauri-bundler-nsis-args.md

Co-authored-by: Lucas Fernandes Nogueira <lucas@tauri.studio>

* Update .changes/tauri-updater-retain-args.md

Co-authored-by: Lucas Fernandes Nogueira <lucas@tauri.studio>

* more typos

* fix update args

* pull args from Env

* check if not empty

* pin memchr

* Update core.rs

* Update core.rs

* move /args

* fix build

* lint

* more lints

---------

Co-authored-by: Lucas Fernandes Nogueira <lucas@tauri.studio>
2024-01-31 16:02:48 -03:00
Fabian-Lars
0bff8c325d fix(cli): Ignore query parameter in dev server (#8697)
* fix(cli): Ignore query parameter in dev server

fixes #8148
additional ref: https://discord.com/channels/616186924390023171/1201199918379974766

* Update .changes/cli-devserver-queryparam.md

---------

Co-authored-by: Amr Bashir <amr.bashir2015@gmail.com>
2024-01-29 14:58:23 +02:00
Fabian-Lars
a9b2c0625c chore: Commit Cargo.lock (#8586)
* chore: Commit Cargo.lock

* memchr for non-windows

* cfg-expr for non-windows

* add msrv check to covector

* update script

* downgrade arboard

* downgrade petgraph

---------

Co-authored-by: Lucas Nogueira <lucas@tauri.app>
2024-01-17 16:21:45 -03:00
Naman Garg
7aa30dec85 feat: Add Section, Priority and Changelog options (#8620)
* Init section, priority and changelog

* Add section. priority and changelog support

* fix variable name

* Add .changes file

* Fix Formatting

* Apply suggestions from code review
2024-01-17 04:21:46 +02:00
Naman Garg
4926648751 deps: Libflate to flate2 (#8618)
* Replace libflate with flate2

* Add .changes file

* Cargo fmt
2024-01-16 15:52:19 +02:00
Amr Bashir
06890c70c6 feat: enable socks-proxy for bundler download (#8596) (#8611)
* feat: enable socks-proxy for bundler download

* change file

Co-authored-by: Lai Zn <laizenan@gmail.com>
2024-01-16 15:42:53 +02:00
阿良仔
1ca69bcf2f fix(clipboard): build issues on wayland (fix #8515) (#8546)
* fix(clipboard): fail to build on wayland

* specify exact version

* bump MSRV to 1.63

* revert msrv changes

---------

Co-authored-by: Amr Bashir <amr.bashir2015@gmail.com>
2024-01-15 19:52:49 +02:00
Naman Garg
6bdba1f330 fix(bundler/deb): use lintian-compliant permissions , closes #7992 (#8585) 2024-01-15 18:08:07 +02:00
Fabian-Lars
b546b42db7 fix(core): Retain order of map keys in ipc, fixes #7922 (#8577)
* fix(core): Retain order of map keys in ipc, fixes #7922

* enable dep on http-api feature instead of http-request

* Create fix-formbody-order.md

* Update fix-formbody-order.md
2024-01-10 21:03:25 +02:00
Fabian-Lars
67d7877f27 fix(cli): Watch workspace members if tauri dir is workspace root (#8520)
* fix(cli): Watch workspace members if tauri dir is ws root

See title. This PR also includes a fix/workaround for paths with funny characters that may not make the glob expansion panic.

Fixes #8509

* extract into function

* cleanup
2024-01-04 01:37:05 +02:00
Jason Tsai
89911296e4 feat(bundler): codesign nested code on macos (#8259)
* feat(bundler): codesign nested code on macos

* chore: update changelog tag

* typo

* also sign stuff in the Libraries folder

tested this for spacedrive, which has a bunch of dylib inside the libraries folder

* Update .changes/mac-bundler-nested-code-sign.md [skip ci]

---------

Co-authored-by: Lucas Nogueira <lucas@tauri.app>
2023-12-28 13:58:24 -03:00
Amr Bashir
8f8729d918 fix(core): allow canceling data-tauri-drag-region maximization on macOS, closes #8306 (#8312)
* fix(core): allow canceling `data-tauri-drag-region` maximization on macOS, closes #8306

* Update .changes/tauri-data-drag-region-macos-maximize.md

* fix typo

* cancel if mouse moves

* Update tauri-data-drag-region-macos-maximize.md

[skip ci]

* Update core/tauri/scripts/core.js [skip ci]

---------

Co-authored-by: Lucas Fernandes Nogueira <lucas@tauri.app>
2023-12-28 09:13:48 -03:00
Amr Bashir
446fc99bbe ci: use default options for repository-dispatch (#8456) 2023-12-27 13:00:37 -03:00
Amr Bashir
6e48837860 feat: re-export Url (#8474)
* feat: re-exoprt `Url`

`Url` is used/returned from public API, we should re-export it

* Update .changes/export-url.md
2023-12-27 12:59:26 -03:00
renovate[bot]
883e52153e chore(deps) Update Tauri API Definitions (1.x) (#8449)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-20 14:16:58 -03:00
amrbashir
32c61f8f23 fix change files 2023-09-10 01:58:17 +03:00
amrbashir
7b8c23aa37 feat(cli): expose a function to kill dev child 2023-09-10 01:54:15 +03:00
54 changed files with 6451 additions and 320 deletions

View File

@@ -0,0 +1,5 @@
---
"tauri-bundler": patch:feat
---
Add `priority`, `section` and `changelog` options in Debian config.

View File

@@ -0,0 +1,5 @@
---
"tauri-bundler": patch:enhance
---
Support using socks proxy from environment when downloading files.

View File

@@ -0,0 +1,6 @@
---
'tauri-cli': 'patch:bug'
'@tauri-apps/cli': 'patch:bug'
---
Fix `fail to rename app` when using `--profile dev`.

View File

@@ -0,0 +1,6 @@
---
"tauri-cli": patch:bug
"@tauri-apps/cli": patch:bug
---
Fix the built-in dev server failing to serve files when URL had queries `?` and other url components.

View File

@@ -0,0 +1,5 @@
---
'@tauri-apps/cli': 'minor:feat'
---
Add `killDevApp` API to kill the dev app process manually.

View File

@@ -0,0 +1,5 @@
---
'tauri-cli': 'minor:feat'
---
Add `tauri_cli::kill_dev_app` API to kill the dev app process manually.

View File

@@ -0,0 +1,6 @@
---
"tauri-cli": patch:bug
"@tauri-apps/cli": patch:bug
---
The cli now also watches cargo workspace members if the tauri folder is the workspace root.

5
.changes/export-url.md Normal file
View File

@@ -0,0 +1,5 @@
---
'tauri': 'patch:feat'
---
Re-export `Url` type.

View File

@@ -0,0 +1,5 @@
---
"tauri": patch:bug
---
Fixes a deadlock when reading a stdout or stderr line returns an error.

View File

@@ -0,0 +1,5 @@
---
'tauri': 'patch:bug'
---
Preserve the order of JS object/map keys in IPC calls. This also fixes issues with the JS `http` module when calling to servers that required a specific order of `FormBody` contents.

View File

@@ -0,0 +1,6 @@
---
'tauri-bundler': 'patch:bug'
---
Fix the `non-standard-file-perm` and `non-standard-dir-perm` issue in Debian packages

View File

@@ -0,0 +1,5 @@
---
"tauri-bundler": patch:deps
---
Replace `libflate` with `flate2` , this will help to provide additional functionalities and features.

View File

@@ -0,0 +1,6 @@
---
"tauri-cli": patch:feat
"tauri-bundler": patch:feat
---
On macOS, support for signing nested .dylib, .app, .xpc and .framework under predefined directories inside the bundled frameworks ("MacOS", "Frameworks", "Plugins", "Helpers", "XPCServices" and "Libraries").

View File

@@ -0,0 +1,5 @@
---
tauri-runtime-wry: patch:bug
---
Add missing `arboard` feature flag to prevent panics in wayland session.

View File

@@ -0,0 +1,5 @@
---
'tauri-bundler': 'minor:feat'
---
On Windows, NSIS installer now supports `/ARGS` flag to pass arguments to be used when launching the app after installation, only works if `/R` is used.

View File

@@ -0,0 +1,5 @@
---
'tauri': 'patch:bug'
---
On macOS, allow cancelling maximization when doubleclick happens on `data-tauri-drag-region` by simply keeping the left moust button pressed and then moving the mouse away of the starting position of the click, which is consistent with the native behavior of macOS.

View File

@@ -0,0 +1,5 @@
---
'tauri': 'minor:enhance'
---
On Windows, retain command line args when relaunching the app after an update. Supports NSIS and WiX (without elevated update task).

View File

@@ -10,8 +10,101 @@ on:
- 1.x
jobs:
msrv-list:
runs-on: ${{ matrix.platform.os }}
strategy:
fail-fast: false
matrix:
platform:
- {
target: x86_64-pc-windows-msvc,
os: windows-latest,
toolchain: '1.61.0'
}
- {
target: x86_64-unknown-linux-gnu,
os: ubuntu-latest,
toolchain: '1.60.0'
}
- {
target: x86_64-apple-darwin,
os: macos-latest,
toolchain: '1.60.0'
}
steps:
- uses: actions/checkout@v4
- name: install rust ${{ matrix.platform.toolchain }}
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ matrix.platform.toolchain }}
target: ${{ matrix.platform.target }}
override: true
default: true
- name: install Linux dependencies
if: contains(matrix.platform.target, 'unknown-linux')
run: |
sudo apt-get update
sudo apt-get install -y webkit2gtk-4.0 libayatana-appindicator3-dev
- uses: Swatinem/rust-cache@v2
- name: delete lockfile
run: rm Cargo.lock
- name: Downgrade crates with MSRV conflict
# The --precise flag can only be used once per invocation.
run: |
cargo update -p system-deps:6.2.0 --precise 6.1.1
cargo update -p toml:0.7.8 --precise 0.7.3
cargo update -p toml_edit:0.19.15 --precise 0.19.8
cargo update -p embed-resource --precise 2.3.0
cargo update -p toml_datetime --precise 0.6.1
cargo update -p serde_spanned --precise 0.6.1
cargo update -p winnow --precise 0.4.1
cargo update -p plist --precise 1.5.1
cargo update -p time --precise 0.3.15
cargo update -p ignore --precise 0.4.18
cargo update -p raw-window-handle --precise 0.5.0
cargo update -p cargo_toml:0.15.3 --precise 0.15.2
cargo update -p zbus --precise 3.13.0
cargo update -p zbus_names --precise 2.5.0
cargo update -p colored --precise 2.0.2
cargo update -p tempfile --precise 3.6.0
cargo update -p serde_with:3.4.0 --precise 3.0.0
cargo update -p tokio --precise 1.29.0
cargo update -p flate2 --precise 1.0.26
cargo update -p h2 --precise 0.3.20
cargo update -p reqwest --precise 0.11.18
cargo update -p bstr --precise 1.6.2
cargo update -p cfg-expr:0.15.6 --precise 0.15.4
cargo update -p memchr --precise 2.6.2
cargo update -p async-executor --precise 1.5.1
cargo update -p proptest --precise 1.2.0
cargo update -p regex --precise 1.9.6
cargo update -p bstr --precise 1.6.2
cargo update -p backtrace --precise 0.3.68
cargo update -p blocking --precise 1.4.1
cargo update -p ignore --precise 0.4.18
cargo update -p regex --precise 1.9.6
cargo update -p globset --precise 0.4.13
cargo update -p crossbeam-channel --precise 0.5.8
cargo update -p crossbeam-utils --precise 0.8.16
cargo update -p image --precise 0.24.4
cargo update -p async-process --precise 1.7.0
cargo update -p is-terminal --precise 0.4.7
cargo update -p tar --precise 0.4.39
cargo update -p serde_json --precise 1.0.97
cargo update -p arboard --precise 3.2.1
cargo update -p petgraph --precise 0.6.3
- name: test build
run: cargo check --target ${{ matrix.platform.target }} --features tracing,compression,wry,linux-protocol-headers,isolation,custom-protocol,api-all,cli,updater,system-tray,windows7-compat,http-multipart,test,
run-integration-tests:
runs-on: ${{ matrix.platform }}
needs: msrv-list
strategy:
fail-fast: false
@@ -19,7 +112,7 @@ jobs:
platform: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: install stable
@@ -66,7 +159,7 @@ jobs:
- run-integration-tests
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v2
@@ -121,8 +214,6 @@ jobs:
contains(steps.covector.outputs.packagesPublished, '@tauri-apps/cli')
uses: peter-evans/repository-dispatch@v1
with:
token: ${{ secrets.ORG_TAURI_BOT_PAT }}
repository: tauri-apps/tauri
event-type: publish-js-cli
client-payload: >-
{"releaseId": "${{ steps.covector.outputs['-tauri-apps-cli-releaseId'] }}" }
@@ -133,6 +224,4 @@ jobs:
contains(steps.covector.outputs.packagesPublished, 'tauri-cli')
uses: peter-evans/repository-dispatch@v1
with:
token: ${{ secrets.ORG_TAURI_BOT_PAT }}
repository: tauri-apps/tauri
event-type: publish-clirs

View File

@@ -121,8 +121,6 @@ jobs:
contains(steps.covector.outputs.packagesPublished, '@tauri-apps/cli')
uses: peter-evans/repository-dispatch@v1
with:
token: ${{ secrets.ORG_TAURI_BOT_PAT }}
repository: tauri-apps/tauri
event-type: publish-js-cli
client-payload: >-
{"releaseId": "${{ steps.covector.outputs['-tauri-apps-cli-releaseId'] }}" }
@@ -133,6 +131,4 @@ jobs:
contains(steps.covector.outputs.packagesPublished, 'tauri-cli')
uses: peter-evans/repository-dispatch@v1
with:
token: ${{ secrets.ORG_TAURI_BOT_PAT }}
repository: tauri-apps/tauri
event-type: publish-clirs

View File

@@ -82,47 +82,5 @@ jobs:
workspaces: core -> ../target
save-if: ${{ matrix.features.key == 'all' }}
- name: Downgrade crates with MSRV conflict
# The --precise flag can only be used once per invocation.
run: |
cargo update -p system-deps:6.2.0 --precise 6.1.1
cargo update -p toml:0.7.8 --precise 0.7.3
cargo update -p toml_edit:0.19.15 --precise 0.19.8
cargo update -p embed-resource --precise 2.3.0
cargo update -p toml_datetime --precise 0.6.1
cargo update -p serde_spanned --precise 0.6.1
cargo update -p winnow --precise 0.4.1
cargo update -p plist --precise 1.5.1
cargo update -p time --precise 0.3.15
cargo update -p ignore --precise 0.4.18
cargo update -p raw-window-handle --precise 0.5.0
cargo update -p cargo_toml:0.15.3 --precise 0.15.2
cargo update -p zbus --precise 3.13.0
cargo update -p zbus_names --precise 2.5.0
cargo update -p colored --precise 2.0.2
cargo update -p tempfile --precise 3.6.0
cargo update -p serde_with:3.4.0 --precise 3.0.0
cargo update -p tokio --precise 1.29.0
cargo update -p flate2 --precise 1.0.26
cargo update -p h2 --precise 0.3.20
cargo update -p reqwest --precise 0.11.18
cargo update -p cfg-expr:0.15.5 --precise 0.15.4
cargo update -p memchr --precise 2.6.2
cargo update -p async-executor --precise 1.5.1
cargo update -p proptest --precise 1.2.0
cargo update -p regex --precise 1.9.6
cargo update -p bstr --precise 1.6.2
cargo update -p backtrace --precise 0.3.68
cargo update -p blocking --precise 1.4.1
cargo update -p ignore --precise 0.4.18
cargo update -p regex --precise 1.9.6
cargo update -p globset --precise 0.4.13
cargo update -p crossbeam-channel --precise 0.5.8
cargo update -p crossbeam-utils --precise 0.8.16
cargo update -p image --precise 0.24.4
cargo update -p async-process --precise 1.7.0
cargo update -p is-terminal --precise 0.4.7
cargo update -p tar --precise 0.4.39
- name: test
run: cargo test --target ${{ matrix.platform.target }} ${{ matrix.features.args }}

2
.gitignore vendored
View File

@@ -73,7 +73,7 @@ TODO.md
target
# lock for libs
/Cargo.lock
#/Cargo.lock Committed to prevent msrv checks from failing
/tooling/bench/tests/Cargo.lock
/yarn.lock

5727
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1320,6 +1320,27 @@
"string",
"null"
]
},
"section": {
"description": "Define the section in Debian Control file. See : https://www.debian.org/doc/debian-policy/ch-archive.html#s-subsections",
"type": [
"string",
"null"
]
},
"priority": {
"description": "Change the priority of the Debian Package. By default, it is set to `optional`. Recognized Priorities as of now are : `required`, `important`, `standard`, `optional`, `extra`",
"type": [
"string",
"null"
]
},
"changelog": {
"description": "Path of the uncompressed Changelog file, to be stored at /usr/share/doc/package-name/changelog.gz. See https://www.debian.org/doc/debian-policy/ch-docs.html#changelog-files-and-release-notes",
"type": [
"string",
"null"
]
}
},
"additionalProperties": false

View File

@@ -48,6 +48,6 @@ macos-private-api = [
]
objc-exception = [ "wry/objc-exception" ]
global-shortcut = [ "tauri-runtime/global-shortcut" ]
clipboard = [ "tauri-runtime/clipboard", "arboard" ]
clipboard = [ "tauri-runtime/clipboard", "arboard/wayland-data-control" ]
linux-headers = [ "wry/linux-headers", "webkit2gtk/v2_36" ]
tracing = [ "dep:tracing", "wry/tracing" ]

View File

@@ -3,10 +3,7 @@
// SPDX-License-Identifier: MIT
pub use tauri_runtime::{
menu::{
Menu, MenuEntry, MenuItem, MenuUpdate, Submenu, SystemTrayMenu, SystemTrayMenuEntry,
SystemTrayMenuItem, TrayHandle,
},
menu::{MenuUpdate, SystemTrayMenu, SystemTrayMenuEntry, SystemTrayMenuItem, TrayHandle},
Icon, SystemTrayEvent,
};
use wry::application::event_loop::EventLoopWindowTarget;

View File

@@ -280,6 +280,14 @@ pub struct DebConfig {
///
/// Available variables: `categories`, `comment` (optional), `exec`, `icon` and `name`.
pub desktop_template: Option<PathBuf>,
/// Define the section in Debian Control file. See : https://www.debian.org/doc/debian-policy/ch-archive.html#s-subsections
pub section: Option<String>,
/// Change the priority of the Debian Package. By default, it is set to `optional`.
/// Recognized Priorities as of now are : `required`, `important`, `standard`, `optional`, `extra`
pub priority: Option<String>,
/// Path of the uncompressed Changelog file, to be stored at /usr/share/doc/package-name/changelog.gz. See
/// https://www.debian.org/doc/debian-policy/ch-docs.html#changelog-files-and-release-notes
pub changelog: Option<PathBuf>,
}
fn de_minimum_system_version<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
@@ -2578,6 +2586,9 @@ impl WindowsUpdateInstallMode {
}
/// Returns the associated nsis arguments.
///
/// [WindowsUpdateInstallMode::Passive] will return `["/P", "/R"]`
/// [WindowsUpdateInstallMode::Quiet] will return `["/S", "/R"]`
pub fn nsis_args(&self) -> &'static [&'static str] {
match self {
Self::Passive => &["/P", "/R"],

View File

@@ -49,7 +49,7 @@ targets = [
normal = [ "reqwest" ]
[dependencies]
serde_json = { version = "1.0", features = [ "raw_value" ] }
serde_json = { version = "1.0", features = [ "raw_value", "preserve_order" ] }
serde = { version = "1.0", features = [ "derive" ] }
tokio = { version = "1", features = [ "rt", "rt-multi-thread", "sync", "fs", "io-util" ] }
futures-util = "0.3"
@@ -95,6 +95,7 @@ ico = { version = "0.2.0", optional = true }
encoding_rs = "0.8.31"
sys-locale = { version = "0.2.3", optional = true }
tracing = { version = "0.1", optional = true }
indexmap = { version = "1", features = [ "std", "serde" ], optional = true }
[target."cfg(any(target_os = \"macos\", windows, target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]
rfd = { version = "0.10", optional = true, features = [ "gtk3", "common-controls-v6" ] }
@@ -111,6 +112,7 @@ cocoa = "0.24"
objc = "0.2"
[target."cfg(windows)".dependencies]
dunce = "1"
webview2-com = "0.19.1"
win7-notifications = { version = "0.4", optional = true }
@@ -156,7 +158,7 @@ updater = [
"dialog-ask",
"fs-extract-api"
]
http-api = [ "reqwest", "bytes" ]
http-api = [ "reqwest", "bytes", "indexmap" ]
http-multipart = [ "reqwest/multipart" ]
os-api = [ "sys-locale" ]
shell-open-api = [ "open", "regex", "tauri-macros/shell-scope" ]

View File

@@ -142,16 +142,40 @@
)
}
// drag region
//-----------------------//
// data-tauri-drag-region
//
// drag on mousedown and maximize on double click on Windows and Linux
// while macOS macos maximization should be on mouseup and if the mouse
// moves after the double click, it should be cancelled (see https://github.com/tauri-apps/tauri/issues/8306)
//-----------------------//
const TAURI_DRAG_REGION_ATTR = 'data-tauri-drag-region';
let x = 0, y = 0;
document.addEventListener('mousedown', (e) => {
if (e.target.hasAttribute('data-tauri-drag-region') && e.button === 0) {
if (
// element has the magic data attribute
e.target.hasAttribute(TAURI_DRAG_REGION_ATTR) &&
// and was left mouse button
e.button === 0 &&
// and was normal click to drag or double click to maximize
(e.detail === 1 || e.detail === 2)
) {
// macOS maximization happens on `mouseup`,
// so we save needed state and early return
if (osName === 'macos' && e.detail == 2) {
x = e.clientX
y = e.clientY
return
}
// prevents text cursor
e.preventDefault()
// fix #2549: double click on drag region edge causes content to maximize without window sizing change
// https://github.com/tauri-apps/tauri/issues/2549#issuecomment-1250036908
e.stopImmediatePropagation()
// start dragging if the element has a `tauri-drag-region` data attribute and maximize on double-clicking it
window.__TAURI_INVOKE__('tauri', {
__tauriModule: 'Window',
message: {
@@ -165,6 +189,34 @@
})
}
})
// on macOS we maximze on mouseup instead, to match the system behavior where maximization can be canceled
// if the mouse moves outside the data-tauri-drag-region
if (osName === "macos") {
document.addEventListener('mouseup', (e) => {
if (
// element has the magic data attribute
e.target.hasAttribute(TAURI_DRAG_REGION_ATTR) &&
// and was left mouse button
e.button === 0 &&
// and was double click
e.detail === 2 &&
// and the cursor hasn't moved from initial mousedown
e.clientX === x && e.clientY === y
) {
window.__TAURI_INVOKE__('tauri', {
__tauriModule: 'Window',
message: {
cmd: 'manage',
data: {
cmd: {
type: '__toggleMaximize'
}
}
}
})
}
})
}
let permissionSettable = false
let permissionValue = 'default'

View File

@@ -250,11 +250,16 @@ pub enum FormPart {
/// Form body definition.
#[derive(Debug, Deserialize)]
pub struct FormBody(pub(crate) HashMap<String, FormPart>);
pub struct FormBody(pub(crate) indexmap::IndexMap<String, FormPart>);
impl FormBody {
/// Creates a new form body.
pub fn new(data: HashMap<String, FormPart>) -> Self {
Self(indexmap::IndexMap::from_iter(data))
}
/// Creates a new form body with pre-ordered keys. Useful if the api requires a specific order.
pub fn new_ordered(data: indexmap::IndexMap<String, FormPart>) -> Self {
Self(data)
}
}

View File

@@ -420,6 +420,7 @@ fn spawn_pipe_reader<F: Fn(String) -> CommandEvent + Send + Copy + 'static>(
Err(e) => {
let tx_ = tx.clone();
let _ = block_on_task(async move { tx_.send(CommandEvent::Error(e.to_string())).await });
break;
}
}
}

View File

@@ -225,6 +225,57 @@ impl Listeners {
}
}
pub fn unlisten_js(listeners_object_name: String, event_name: String, event_id: u32) -> String {
format!(
"
(function () {{
const listeners = (window['{listeners_object_name}'] || {{}})['{event_name}']
if (listeners) {{
const index = window['{listeners_object_name}']['{event_name}'].findIndex(e => e.id === {event_id})
if (index > -1) {{
window['{listeners_object_name}']['{event_name}'].splice(index, 1)
}}
}}
}})()
",
)
}
pub fn listen_js(
listeners_object_name: String,
event: String,
event_id: u32,
window_label: Option<String>,
handler: String,
) -> String {
format!(
"
(function () {{
if (window['{listeners}'] === void 0) {{
Object.defineProperty(window, '{listeners}', {{ value: Object.create(null) }});
}}
if (window['{listeners}'][{event}] === void 0) {{
Object.defineProperty(window['{listeners}'], {event}, {{ value: [] }});
}}
const eventListeners = window['{listeners}'][{event}]
const listener = {{
id: {event_id},
windowLabel: {window_label},
handler: {handler}
}};
eventListeners.push(listener);
}})()
",
listeners = listeners_object_name,
window_label = if let Some(l) = window_label {
crate::runtime::window::assert_label_is_valid(&l);
format!("'{l}'")
} else {
"null".to_owned()
},
)
}
#[cfg(test)]
mod test {
use super::*;
@@ -298,54 +349,3 @@ mod test {
}
}
}
pub fn unlisten_js(listeners_object_name: String, event_name: String, event_id: u32) -> String {
format!(
"
(function () {{
const listeners = (window['{listeners_object_name}'] || {{}})['{event_name}']
if (listeners) {{
const index = window['{listeners_object_name}']['{event_name}'].findIndex(e => e.id === {event_id})
if (index > -1) {{
window['{listeners_object_name}']['{event_name}'].splice(index, 1)
}}
}}
}})()
",
)
}
pub fn listen_js(
listeners_object_name: String,
event: String,
event_id: u32,
window_label: Option<String>,
handler: String,
) -> String {
format!(
"
(function () {{
if (window['{listeners}'] === void 0) {{
Object.defineProperty(window, '{listeners}', {{ value: Object.create(null) }});
}}
if (window['{listeners}'][{event}] === void 0) {{
Object.defineProperty(window['{listeners}'], {event}, {{ value: [] }});
}}
const eventListeners = window['{listeners}'][{event}]
const listener = {{
id: {event_id},
windowLabel: {window_label},
handler: {handler}
}};
eventListeners.push(listener);
}})()
",
listeners = listeners_object_name,
window_label = if let Some(l) = window_label {
crate::runtime::window::assert_label_is_valid(&l);
format!("'{l}'")
} else {
"null".to_owned()
},
)
}

View File

@@ -176,6 +176,8 @@ pub use error::Error;
pub use regex;
pub use tauri_macros::{command, generate_handler};
pub use url::Url;
pub mod api;
pub(crate) mod app;
pub mod async_runtime;

View File

@@ -706,6 +706,7 @@ impl<R: Runtime> Update<R> {
&self.extract_path,
self.with_elevated_task,
&self.app.config(),
&self.app.env(),
)?;
#[cfg(not(target_os = "windows"))]
copy_files_and_run(archive_buffer, &self.extract_path)?;
@@ -805,6 +806,7 @@ fn copy_files_and_run<R: Read + Seek>(
_extract_path: &Path,
with_elevated_task: bool,
config: &crate::Config,
env: &crate::Env,
) -> Result {
// FIXME: We need to create a memory buffer with the MSI and then run it.
// (instead of extracting the MSI to a temp path)
@@ -830,6 +832,8 @@ fn copy_files_and_run<R: Read + Seek>(
|p| format!("{p}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"),
);
let current_exe_args = env.args.clone();
for path in paths {
let found_path = path?.path();
// we support 2 type of files exe & msi for now
@@ -842,29 +846,39 @@ fn copy_files_and_run<R: Read + Seek>(
installer_path.push("\"");
let installer_args = [
config.tauri.updater.windows.install_mode.nsis_args(),
config
.tauri
.updater
.windows
.install_mode
.nsis_args()
.iter()
.map(ToString::to_string)
.collect(),
vec!["/ARGS".to_string()],
current_exe_args,
config
.tauri
.updater
.windows
.installer_args
.iter()
.map(AsRef::as_ref)
.collect::<Vec<_>>()
.as_slice(),
.map(ToString::to_string)
.collect::<Vec<_>>(),
]
.concat();
// Run the EXE
let mut cmd = Command::new(powershell_path);
cmd
.args(["-NoProfile", "-WindowStyle", "Hidden"])
.args(["Start-Process"])
.args(["-NoProfile", "-WindowStyle", "Hidden", "Start-Process"])
.arg(installer_path);
if !installer_args.is_empty() {
cmd.arg("-ArgumentList").arg(installer_args.join(", "));
}
cmd.spawn().expect("installer failed to start");
cmd
.spawn()
.expect("Running NSIS installer from powershell has failed to start");
exit(0);
} else if found_path.extension() == Some(OsStr::new("msi")) {
@@ -908,10 +922,10 @@ fn copy_files_and_run<R: Read + Seek>(
}
// we need to wrap the current exe path in quotes for Start-Process
let mut current_exe_arg = std::ffi::OsString::new();
current_exe_arg.push("\"");
current_exe_arg.push(current_exe()?);
current_exe_arg.push("\"");
let mut current_executable = std::ffi::OsString::new();
current_executable.push("\"");
current_executable.push(dunce::simplified(&current_exe()?));
current_executable.push("\"");
let mut msi_path = std::ffi::OsString::new();
msi_path.push("\"\"\"");
@@ -933,7 +947,9 @@ fn copy_files_and_run<R: Read + Seek>(
.concat();
// run the installer and relaunch the application
let powershell_install_res = Command::new(powershell_path)
let mut powershell_cmd = Command::new(powershell_path);
powershell_cmd
.args(["-NoProfile", "-WindowStyle", "Hidden"])
.args([
"Start-Process",
@@ -946,8 +962,15 @@ fn copy_files_and_run<R: Read + Seek>(
.arg(&msi_path)
.arg(format!(", {}, /promptrestart;", installer_args.join(", ")))
.arg("Start-Process")
.arg(current_exe_arg)
.spawn();
.arg(current_executable);
if !current_exe_args.is_empty() {
powershell_cmd
.arg("-ArgumentList")
.arg(current_exe_args.join(", "));
}
let powershell_install_res = powershell_cmd.spawn();
if powershell_install_res.is_err() {
// fallback to running msiexec directly - relaunch won't be available
// we use this here in case powershell fails in an older machine somehow

View File

@@ -45,21 +45,21 @@
"devDependencies": {
"@rollup/plugin-terser": "0.4.4",
"@rollup/plugin-typescript": "11.1.5",
"@types/node": "20.9.0",
"@types/node": "20.10.5",
"@typescript-eslint/eslint-plugin": "5.62.0",
"eslint-config-standard-with-typescript": "34.0.1",
"@typescript-eslint/parser": "5.62.0",
"eslint": "8.53.0",
"eslint": "8.56.0",
"eslint-config-prettier": "8.10.0",
"eslint-plugin-import": "2.29.0",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-n": "15.7.0",
"eslint-plugin-node": "11.1.0",
"eslint-plugin-promise": "6.1.1",
"eslint-plugin-security": "1.7.1",
"fast-glob": "3.3.2",
"prettier": "3.0.3",
"prettier": "3.1.1",
"rollup": "3.29.4",
"typescript": "5.2.2"
"typescript": "5.3.3"
},
"engines": {
"node": ">= 14.6.0",

View File

@@ -24,10 +24,10 @@
resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.6.2.tgz#1816b5f6948029c5eaacb0703b850ee0cb37d8f8"
integrity sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==
"@eslint/eslintrc@^2.1.3":
version "2.1.3"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.3.tgz#797470a75fe0fbd5a53350ee715e85e87baff22d"
integrity sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==
"@eslint/eslintrc@^2.1.4":
version "2.1.4"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad"
integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==
dependencies:
ajv "^6.12.4"
debug "^4.3.2"
@@ -39,10 +39,10 @@
minimatch "^3.1.2"
strip-json-comments "^3.1.1"
"@eslint/js@8.53.0":
version "8.53.0"
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.53.0.tgz#bea56f2ed2b5baea164348ff4d5a879f6f81f20d"
integrity sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w==
"@eslint/js@8.56.0":
version "8.56.0"
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.56.0.tgz#ef20350fec605a7f7035a01764731b2de0f3782b"
integrity sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==
"@humanwhocodes/config-array@^0.11.13":
version "0.11.13"
@@ -165,10 +165,10 @@
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
"@types/node@20.9.0":
version "20.9.0"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.9.0.tgz#bfcdc230583aeb891cf51e73cfdaacdd8deae298"
integrity sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==
"@types/node@20.10.5":
version "20.10.5"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.10.5.tgz#47ad460b514096b7ed63a1dae26fad0914ed3ab2"
integrity sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==
dependencies:
undici-types "~5.26.4"
@@ -664,10 +664,10 @@ eslint-plugin-es@^4.1.0:
eslint-utils "^2.0.0"
regexpp "^3.0.0"
eslint-plugin-import@2.29.0:
version "2.29.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.29.0.tgz#8133232e4329ee344f2f612885ac3073b0b7e155"
integrity sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg==
eslint-plugin-import@2.29.1:
version "2.29.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz#d45b37b5ef5901d639c15270d74d46d161150643"
integrity sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==
dependencies:
array-includes "^3.1.7"
array.prototype.findlastindex "^1.2.3"
@@ -685,7 +685,7 @@ eslint-plugin-import@2.29.0:
object.groupby "^1.0.1"
object.values "^1.1.7"
semver "^6.3.1"
tsconfig-paths "^3.14.2"
tsconfig-paths "^3.15.0"
eslint-plugin-n@15.7.0:
version "15.7.0"
@@ -780,15 +780,15 @@ eslint-visitor-keys@^3.4.3:
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800"
integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
eslint@8.53.0:
version "8.53.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.53.0.tgz#14f2c8244298fcae1f46945459577413ba2697ce"
integrity sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==
eslint@8.56.0:
version "8.56.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.56.0.tgz#4957ce8da409dc0809f99ab07a1b94832ab74b15"
integrity sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==
dependencies:
"@eslint-community/eslint-utils" "^4.2.0"
"@eslint-community/regexpp" "^4.6.1"
"@eslint/eslintrc" "^2.1.3"
"@eslint/js" "8.53.0"
"@eslint/eslintrc" "^2.1.4"
"@eslint/js" "8.56.0"
"@humanwhocodes/config-array" "^0.11.13"
"@humanwhocodes/module-importer" "^1.0.1"
"@nodelib/fs.walk" "^1.2.8"
@@ -1593,10 +1593,10 @@ prelude-ls@^1.2.1:
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
prettier@3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.0.3.tgz#432a51f7ba422d1469096c0fdc28e235db8f9643"
integrity sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==
prettier@3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.1.1.tgz#6ba9f23165d690b6cbdaa88cb0807278f7019848"
integrity sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==
punycode@^2.1.0:
version "2.1.1"
@@ -1883,10 +1883,10 @@ to-regex-range@^5.0.1:
dependencies:
is-number "^7.0.0"
tsconfig-paths@^3.14.2:
version "3.14.2"
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz#6e32f1f79412decd261f92d633a9dc1cfa99f088"
integrity sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==
tsconfig-paths@^3.15.0:
version "3.15.0"
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4"
integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==
dependencies:
"@types/json5" "^0.0.29"
json5 "^1.0.2"
@@ -1956,10 +1956,10 @@ typed-array-length@^1.0.4:
for-each "^0.3.3"
is-typed-array "^1.1.9"
typescript@5.2.2:
version "5.2.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78"
integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==
typescript@5.3.3:
version "5.3.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.3.3.tgz#b3ce6ba258e72e6305ba66f5c9b452aaee3ffe37"
integrity sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==
unbox-primitive@^1.0.2:
version "1.0.2"

View File

@@ -19,7 +19,7 @@ exclude = [ "CHANGELOG.md", "/target", "rustfmt.toml" ]
[dependencies]
tauri-utils = { version = "1.5.2", path = "../../core/tauri-utils", features = [ "resources" ] }
image = "0.24.7"
libflate = "2.0"
flate2 = "1.0"
anyhow = "1.0"
thiserror = "1.0"
serde_json = "1.0"
@@ -32,7 +32,7 @@ tempfile = "3.8.1"
log = { version = "0.4.20", features = [ "kv_unstable" ] }
dirs-next = "2.0"
os_pipe = "1"
ureq = { version = "2.8", default-features = false }
ureq = { version = "2.9.1", default-features = false, features = [ "socks-proxy" ] }
native-tls = { version = "0.2", optional = true }
hex = "0.4"
semver = "1"

View File

@@ -29,9 +29,9 @@ use anyhow::Context;
use handlebars::Handlebars;
use heck::AsKebabCase;
use image::{self, codecs::png::PngDecoder, ImageDecoder};
use libflate::gzip;
use log::info;
use serde::Serialize;
use tar::HeaderMode;
use walkdir::WalkDir;
use std::{
@@ -39,9 +39,12 @@ use std::{
ffi::OsStr,
fs::{self, read_to_string, File},
io::{self, Write},
os::unix::fs::MetadataExt,
path::{Path, PathBuf},
};
use flate2::{write::GzEncoder, Compression};
#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub struct DebIcon {
pub width: u32,
@@ -132,10 +135,30 @@ pub fn generate_data(
let icons =
generate_icon_files(settings, &data_dir).with_context(|| "Failed to create icon files")?;
generate_desktop_file(settings, &data_dir).with_context(|| "Failed to create desktop file")?;
generate_changelog_file(settings, &data_dir)
.with_context(|| "Failed to create changelog.gz file")?;
Ok((data_dir, icons))
}
/// Generate the Changelog file by compressing, to be stored at /usr/share/doc/package-name/changelog.gz. See
/// https://www.debian.org/doc/debian-policy/ch-docs.html#changelog-files-and-release-notes
fn generate_changelog_file(settings: &Settings, data_dir: &Path) -> crate::Result<()> {
if let Some(changelog_src_path) = &settings.deb().changelog {
let mut src_file = File::open(changelog_src_path)?;
let bin_name = settings.main_binary_name();
let dest_path = data_dir.join(format!("usr/share/doc/{}/changelog.gz", bin_name));
let changelog_file = common::create_file(&dest_path)?;
let mut gzip_encoder = GzEncoder::new(changelog_file, Compression::new(9));
io::copy(&mut src_file, &mut gzip_encoder)?;
let mut changelog_file = gzip_encoder.finish()?;
changelog_file.flush()?;
}
Ok(())
}
/// Generate the application desktop file and store it under the `data_dir`.
fn generate_desktop_file(settings: &Settings, data_dir: &Path) -> crate::Result<()> {
let bin_name = settings.main_binary_name();
@@ -209,6 +232,14 @@ fn generate_control_file(
writeln!(file, "Installed-Size: {}", total_dir_size(data_dir)? / 1024)?;
let authors = settings.authors_comma_separated().unwrap_or_default();
writeln!(file, "Maintainer: {}", authors)?;
if let Some(section) = &settings.deb().section {
writeln!(file, "Section: {}", section)?;
}
if let Some(priority) = &settings.deb().priority {
writeln!(file, "Priority: {}", priority)?;
} else {
writeln!(file, "Priority: optional")?;
}
if !settings.homepage_url().is_empty() {
writeln!(file, "Homepage: {}", settings.homepage_url())?;
}
@@ -233,7 +264,6 @@ fn generate_control_file(
writeln!(file, " {}", line)?;
}
}
writeln!(file, "Priority: optional")?;
file.flush()?;
Ok(())
}
@@ -366,20 +396,15 @@ fn create_tar_from_dir<P: AsRef<Path>, W: Write>(src_dir: P, dest_file: W) -> cr
continue;
}
let dest_path = src_path.strip_prefix(src_dir)?;
let stat = fs::metadata(src_path)?;
let mut header = tar::Header::new_gnu();
header.set_metadata_in_mode(&stat, HeaderMode::Deterministic);
header.set_mtime(stat.mtime() as u64);
if entry.file_type().is_dir() {
let stat = fs::metadata(src_path)?;
let mut header = tar::Header::new_gnu();
header.set_metadata(&stat);
header.set_uid(0);
header.set_gid(0);
tar_builder.append_data(&mut header, dest_path, &mut io::empty())?;
} else {
let mut src_file = fs::File::open(src_path)?;
let stat = src_file.metadata()?;
let mut header = tar::Header::new_gnu();
header.set_metadata(&stat);
header.set_uid(0);
header.set_gid(0);
tar_builder.append_data(&mut header, dest_path, &mut src_file)?;
}
}
@@ -394,9 +419,9 @@ fn tar_and_gzip_dir<P: AsRef<Path>>(src_dir: P) -> crate::Result<PathBuf> {
let src_dir = src_dir.as_ref();
let dest_path = src_dir.with_extension("tar.gz");
let dest_file = common::create_file(&dest_path)?;
let gzip_encoder = gzip::Encoder::new(dest_file)?;
let gzip_encoder = GzEncoder::new(dest_file, Compression::default());
let gzip_encoder = create_tar_from_dir(src_dir, gzip_encoder)?;
let mut dest_file = gzip_encoder.finish().into_result()?;
let mut dest_file = gzip_encoder.finish()?;
dest_file.flush()?;
Ok(dest_path)
}

View File

@@ -39,6 +39,15 @@ use std::{
process::Command,
};
const NESTED_CODE_FOLDER: [&str; 6] = [
"MacOS",
"Frameworks",
"Plugins",
"Helpers",
"XPCServices",
"Libraries",
];
/// Bundles the project.
/// Returns a vector of PathBuf that shows where the .app was created.
pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<PathBuf>> {
@@ -77,18 +86,7 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<PathBuf>> {
let framework_paths = copy_frameworks_to_bundle(&bundle_directory, settings)
.with_context(|| "Failed to bundle frameworks")?;
sign_paths.extend(
framework_paths
.into_iter()
.filter(|p| {
let ext = p.extension();
ext == Some(OsStr::new("framework")) || ext == Some(OsStr::new("dylib"))
})
.map(|path| SignTarget {
path,
is_an_executable: false,
}),
);
sign_paths.extend(framework_paths);
settings.copy_resources(&resources_dir)?;
@@ -141,7 +139,7 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<PathBuf>> {
fn remove_extra_attr(app_bundle_path: &Path) -> crate::Result<()> {
Command::new("xattr")
.arg("-cr")
.arg("-crs")
.arg(app_bundle_path)
.output_ok()
.context("failed to remove extra attributes from app bundle")?;
@@ -265,7 +263,7 @@ fn copy_framework_from(dest_dir: &Path, framework: &str, src_dir: &Path) -> crat
fn copy_frameworks_to_bundle(
bundle_directory: &Path,
settings: &Settings,
) -> crate::Result<Vec<PathBuf>> {
) -> crate::Result<Vec<SignTarget>> {
let mut paths = Vec::new();
let frameworks = settings
@@ -288,7 +286,7 @@ fn copy_frameworks_to_bundle(
.expect("Couldn't get framework filename");
let dest_path = dest_dir.join(src_name);
common::copy_dir(&src_path, &dest_path)?;
paths.push(dest_path);
add_framework_sign_path(&src_path, &dest_path, &mut paths);
continue;
} else if framework.ends_with(".dylib") {
let src_path = PathBuf::from(framework);
@@ -301,7 +299,10 @@ fn copy_frameworks_to_bundle(
let src_name = src_path.file_name().expect("Couldn't get library filename");
let dest_path = dest_dir.join(src_name);
common::copy_file(&src_path, &dest_path)?;
paths.push(dest_path);
paths.push(SignTarget {
path: dest_path,
is_an_executable: false,
});
continue;
} else if framework.contains('/') {
return Err(crate::Error::GenericError(format!(
@@ -330,3 +331,90 @@ fn copy_frameworks_to_bundle(
}
Ok(paths)
}
/// Recursively add framework's sign paths.
/// If the framework has multiple versions, it will sign "Current" version by default.
fn add_framework_sign_path(
framework_root: &Path,
dest_path: &Path,
sign_paths: &mut Vec<SignTarget>,
) {
if framework_root.join("Versions/Current").exists() {
add_nested_code_sign_path(
&framework_root.join("Versions/Current"),
&dest_path.join("Versions/Current"),
sign_paths,
);
} else {
add_nested_code_sign_path(framework_root, dest_path, sign_paths);
}
sign_paths.push(SignTarget {
path: dest_path.into(),
is_an_executable: false,
});
}
/// Recursively add executable bundle's sign path (.xpc, .app).
fn add_executable_bundle_sign_path(
bundle_root: &Path,
dest_path: &Path,
sign_paths: &mut Vec<SignTarget>,
) {
if bundle_root.join("Contents").exists() {
add_nested_code_sign_path(
&bundle_root.join("Contents"),
&dest_path.join("Contents"),
sign_paths,
);
} else {
add_nested_code_sign_path(bundle_root, dest_path, sign_paths);
}
sign_paths.push(SignTarget {
path: dest_path.into(),
is_an_executable: true,
});
}
fn add_nested_code_sign_path(src_path: &Path, dest_path: &Path, sign_paths: &mut Vec<SignTarget>) {
for folder_name in NESTED_CODE_FOLDER.iter() {
let src_folder_path = src_path.join(folder_name);
let dest_folder_path = dest_path.join(folder_name);
if src_folder_path.exists() {
for entry in walkdir::WalkDir::new(src_folder_path)
.min_depth(1)
.max_depth(1)
.into_iter()
.filter_map(|e| e.ok())
{
if entry.path_is_symlink() || entry.file_name().to_string_lossy().starts_with('.') {
continue;
}
let dest_path = dest_folder_path.join(entry.file_name());
let ext = entry.path().extension();
if entry.path().is_dir() {
// Bundles, like .app, .framework, .xpc
if ext == Some(OsStr::new("framework")) {
add_framework_sign_path(&entry.clone().into_path(), &dest_path, sign_paths);
} else if ext == Some(OsStr::new("xpc")) || ext == Some(OsStr::new("app")) {
add_executable_bundle_sign_path(&entry.clone().into_path(), &dest_path, sign_paths);
}
} else if entry.path().is_file() {
// Binaries, like .dylib, Mach-O executables
if ext == Some(OsStr::new("dylib")) {
sign_paths.push(SignTarget {
path: dest_path,
is_an_executable: false,
});
} else if ext.is_none() {
sign_paths.push(SignTarget {
path: dest_path,
is_an_executable: true,
});
}
}
}
}
}
}

View File

@@ -185,6 +185,14 @@ pub struct DebianSettings {
#[doc = include_str!("./linux/templates/main.desktop")]
/// ```
pub desktop_template: Option<PathBuf>,
/// Define the section in Debian Control file. See : https://www.debian.org/doc/debian-policy/ch-archive.html#s-subsections
pub section: Option<String>,
/// Change the priority of the Debian Package. By default, it is set to `optional`.
/// Recognized Priorities as of now are : `required`, `important`, `standard`, `optional`, `extra`
pub priority: Option<String>,
/// Path of the uncompressed Changelog file, to be stored at /usr/share/doc/package-name/changelog.gz. See
/// https://www.debian.org/doc/debian-policy/ch-docs.html#changelog-files-and-release-notes
pub changelog: Option<PathBuf>,
}
/// The macOS bundle settings.

View File

@@ -234,12 +234,14 @@ pub fn create_zip(src_file: &Path, dst_file: &Path) -> crate::Result<PathBuf> {
#[cfg(not(target_os = "windows"))]
fn create_tar(src_dir: &Path, dest_path: &Path) -> crate::Result<PathBuf> {
use flate2::{write::GzEncoder, Compression};
let dest_file = common::create_file(dest_path)?;
let gzip_encoder = libflate::gzip::Encoder::new(dest_file)?;
let gzip_encoder = GzEncoder::new(dest_file, Compression::default());
let gzip_encoder = create_tar_from_src(src_dir, gzip_encoder)?;
let mut dest_file = gzip_encoder.finish().into_result()?;
let mut dest_file = gzip_encoder.finish()?;
dest_file.flush()?;
Ok(dest_path.to_owned())
}

View File

@@ -606,7 +606,8 @@ Function .onInstSuccess
check_r_flag:
${GetOptions} $CMDLINE "/R" $R0
IfErrors run_done 0
Exec '"$INSTDIR\${MAINBINARYNAME}.exe"'
${GetOptions} $CMDLINE "/ARGS" $R0
Exec '"$INSTDIR\${MAINBINARYNAME}.exe" $R0'
run_done:
FunctionEnd

74
tooling/cli/Cargo.lock generated
View File

@@ -17,12 +17,6 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "adler32"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
[[package]]
name = "aead"
version = "0.5.2"
@@ -533,15 +527,6 @@ version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
[[package]]
name = "core2"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505"
dependencies = [
"memchr",
]
[[package]]
name = "cpufeatures"
version = "0.2.11"
@@ -711,12 +696,6 @@ dependencies = [
"syn 2.0.39",
]
[[package]]
name = "dary_heap"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7762d17f1241643615821a8455a0b2c3e803784b058693d990b11f2dce25a0ca"
[[package]]
name = "data-encoding"
version = "2.5.0"
@@ -1193,15 +1172,6 @@ version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hashbrown"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
dependencies = [
"ahash",
]
[[package]]
name = "hashbrown"
version = "0.14.3"
@@ -1647,30 +1617,6 @@ version = "0.2.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
[[package]]
name = "libflate"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f7d5654ae1795afc7ff76f4365c2c8791b0feb18e8996a96adad8ffd7c3b2bf"
dependencies = [
"adler32",
"core2",
"crc32fast",
"dary_heap",
"libflate_lz77",
]
[[package]]
name = "libflate_lz77"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be5f52fb8c451576ec6b79d3f4deb327398bc05bbdbd99021a6e77a4c855d524"
dependencies = [
"core2",
"hashbrown 0.13.2",
"rle-decode-fast",
]
[[package]]
name = "libloading"
version = "0.8.1"
@@ -2745,12 +2691,6 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "rle-decode-fast"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422"
[[package]]
name = "rpassword"
version = "7.3.1"
@@ -3212,6 +3152,17 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "socks"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0c3dbbd9ae980613c6dd8e28a9407b50509d3803b57624d5dfe8315218cd58b"
dependencies = [
"byteorder",
"libc",
"winapi",
]
[[package]]
name = "spin"
version = "0.9.8"
@@ -3401,12 +3352,12 @@ dependencies = [
"ar",
"dirs-next",
"dunce",
"flate2",
"glob",
"handlebars",
"heck",
"hex",
"image",
"libflate",
"log",
"md5",
"native-tls",
@@ -3921,6 +3872,7 @@ dependencies = [
"once_cell",
"rustls",
"rustls-webpki",
"socks",
"url",
"webpki-roots",
]

View File

@@ -59,7 +59,7 @@ handlebars = "4.4"
include_dir = "0.7"
minisign = "=0.7.3"
base64 = "0.21.5"
ureq = { version = "2.8", default-features = false, features = [ "gzip" ] }
ureq = { version = "2.9.1", default-features = false, features = [ "gzip" ] }
os_info = "3"
semver = "1.0"
regex = "1.10.2"

View File

@@ -4,4 +4,5 @@
/* auto-generated by NAPI-RS */
export function run(args: Array<string>, binName: string | undefined | null, callback: (...args: any[]) => any): void
export function killDevApp(callback: (...args: any[]) => any): void
export function logError(error: string): void

View File

@@ -252,7 +252,8 @@ if (!nativeBinding) {
throw new Error(`Failed to load native binding`)
}
const { run, logError } = nativeBinding
const { run, killDevApp, logError } = nativeBinding
module.exports.run = run
module.exports.killDevApp = killDevApp
module.exports.logError = logError

View File

@@ -6,3 +6,4 @@
/* eslint-disable */
export function run(args: Array<string>, binName: string | undefined | null): Promise<void>
export function killDevApp(): Promise<void>

View File

@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
const { run, logError } = require('./index')
const { run, killDevApp, logError } = require('./index')
module.exports.run = (args, binName) => {
return new Promise((resolve, reject) => {
@@ -16,4 +16,16 @@ module.exports.run = (args, binName) => {
})
}
module.exports.killDevApp = () => {
return new Promise((resolve, reject) => {
killDevApp(res => {
if (res instanceof Error) {
reject(res)
} else {
resolve(res)
}
})
})
}
module.exports.logError = logError

View File

@@ -25,6 +25,23 @@ pub fn run(args: Vec<String>, bin_name: Option<String>, callback: JsFunction) ->
Ok(())
}
#[napi_derive::napi]
pub fn kill_dev_app(callback: JsFunction) -> Result<()> {
let function: ThreadsafeFunction<bool, ErrorStrategy::CalleeHandled> = callback
.create_threadsafe_function(0, |ctx| ctx.env.get_boolean(ctx.value).map(|v| vec![v]))?;
// we need to run in a separate thread so Node.js (e.g. vue-cli-plugin-tauri) consumers
// can do work while `tauri dev` is running.
std::thread::spawn(move || match tauri_cli::kill_dev_app() {
Ok(_) => function.call(Ok(true), ThreadsafeFunctionCallMode::Blocking),
Err(e) => function.call(
Err(Error::new(Status::GenericFailure, format!("{:#}", e))),
ThreadsafeFunctionCallMode::Blocking,
),
});
Ok(())
}
#[napi_derive::napi]
pub fn log_error(error: String) {
log::error!("{}", error);

View File

@@ -1320,6 +1320,27 @@
"string",
"null"
]
},
"section": {
"description": "Define the section in Debian Control file. See : https://www.debian.org/doc/debian-policy/ch-archive.html#s-subsections",
"type": [
"string",
"null"
]
},
"priority": {
"description": "Change the priority of the Debian Package. By default, it is set to `optional`. Recognized Priorities as of now are : `required`, `important`, `standard`, `optional`, `extra`",
"type": [
"string",
"null"
]
},
"changelog": {
"description": "Path of the uncompressed Changelog file, to be stored at /usr/share/doc/package-name/changelog.gz. See https://www.debian.org/doc/debian-policy/ch-docs.html#changelog-files-and-release-notes",
"type": [
"string",
"null"
]
}
},
"additionalProperties": false

View File

@@ -8,7 +8,7 @@ use crate::{
command_env,
config::{get as get_config, reload as reload_config, AppUrl, BeforeDevCommand, WindowUrl},
},
interface::{AppInterface, ExitReason, Interface},
interface::{rust::DevChild, AppInterface, ExitReason, Interface},
CommandExt, Result,
};
use clap::{ArgAction, Parser};
@@ -27,6 +27,7 @@ use std::{
},
};
pub(crate) static DEV_CHILD: OnceCell<Arc<Mutex<DevChild>>> = OnceCell::new();
static BEFORE_DEV: OnceCell<Mutex<Arc<SharedChild>>> = OnceCell::new();
static KILL_BEFORE_DEV_FLAG: OnceCell<AtomicBool> = OnceCell::new();

View File

@@ -123,11 +123,13 @@ pub fn start_dev_server<P: AsRef<Path>>(path: P, port: Option<u16>) -> crate::Re
}
async fn handler(uri: axum::http::Uri, state: Arc<State>) -> impl IntoResponse {
let uri = uri.to_string();
// Frontend files should not contain query parameters. This seems to be how vite handles it.
let uri = uri.path();
let uri = if uri == "/" {
&uri
uri
} else {
uri.strip_prefix('/').unwrap_or(&uri)
uri.strip_prefix('/').unwrap_or(uri)
};
let file = std::fs::read(state.serve_dir.join(uri))

View File

@@ -92,7 +92,7 @@ pub struct DevChild {
}
impl DevChild {
fn kill(&self) -> std::io::Result<()> {
pub fn kill(&self) -> std::io::Result<()> {
if let Some(child) = &*self.app_child.lock().unwrap() {
child.kill()?;
} else {
@@ -195,11 +195,13 @@ impl Interface for Rust {
if options.no_watch {
let (tx, rx) = sync_channel(1);
self.run_dev(options, move |status, reason| {
let child = self.run_dev(options, move |status, reason| {
tx.send(()).unwrap();
on_exit_(status, reason)
})?;
let _ = crate::dev::DEV_CHILD.set(Arc::new(Mutex::new(child)));
rx.recv().unwrap();
Ok(())
} else {
@@ -207,6 +209,10 @@ impl Interface for Rust {
on_exit_(status, reason)
})?;
let child = Arc::new(Mutex::new(child));
let child_ = Arc::clone(&child);
let _ = crate::dev::DEV_CHILD.set(child_);
self.run_dev_watcher(child, options, on_exit)
}
}
@@ -347,6 +353,40 @@ fn expand_member_path(path: &Path) -> crate::Result<Vec<PathBuf>> {
Ok(res)
}
fn get_watch_folders() -> crate::Result<Vec<PathBuf>> {
let tauri_path = tauri_dir();
let workspace_path = get_workspace_dir()?;
// We always want to watch the main tauri folder.
let mut watch_folders = vec![tauri_path.to_path_buf()];
// We also try to watch workspace members, no matter if the tauri cargo project is the workspace root or a workspace member
let cargo_settings = CargoSettings::load(&workspace_path)?;
if let Some(members) = cargo_settings.workspace.and_then(|w| w.members) {
for p in members {
let p = workspace_path.join(p);
match expand_member_path(&p) {
// Sometimes expand_member_path returns an empty vec, for example if the path contains `[]` as in `C:/[abc]/project/`.
// Cargo won't complain unless theres a workspace.members config with glob patterns so we should support it too.
Ok(expanded_paths) => {
if expanded_paths.is_empty() {
watch_folders.push(p);
} else {
watch_folders.extend(expanded_paths);
}
}
Err(err) => {
// If this fails cargo itself should fail too. But we still try to keep going with the unexpanded path.
error!("Error watching {}: {}", p.display(), err.to_string());
watch_folders.push(p);
}
};
}
}
Ok(watch_folders)
}
impl Rust {
fn run_dev<F: Fn(ExitStatus, ExitReason) + Send + Sync + 'static>(
&mut self,
@@ -405,50 +445,17 @@ impl Rust {
fn run_dev_watcher<F: Fn(ExitStatus, ExitReason) + Send + Sync + 'static>(
&mut self,
child: DevChild,
process: Arc<Mutex<DevChild>>,
options: Options,
on_exit: Arc<F>,
) -> crate::Result<()> {
let process = Arc::new(Mutex::new(child));
let (tx, rx) = sync_channel(1);
let app_path = app_dir();
let tauri_path = tauri_dir();
let workspace_path = get_workspace_dir()?;
let watch_folders = if tauri_path == workspace_path {
vec![tauri_path]
} else {
let cargo_settings = CargoSettings::load(&workspace_path)?;
cargo_settings
.workspace
.as_ref()
.map(|w| {
w.members
.clone()
.unwrap_or_default()
.into_iter()
.map(|p| workspace_path.join(p))
.collect()
})
.unwrap_or_else(|| vec![tauri_path])
};
let watch_folders = get_watch_folders()?;
let watch_folders = watch_folders
.into_iter()
.flat_map(|p| {
match expand_member_path(&p) {
Ok(p) => p,
Err(err) => {
// If this fails cargo itself should fail too. But we still try to keep going with the unexpanded path.
error!("Error watching {}: {}", p.display(), err.to_string());
vec![p]
}
}
})
.collect::<Vec<_>>();
let watch_folders = watch_folders.iter().map(Path::new).collect::<Vec<_>>();
let common_ancestor = common_path::common_path_all(watch_folders.clone()).unwrap();
let common_ancestor = common_path::common_path_all(watch_folders.iter().map(Path::new))
.expect("watch_folders should not be empty");
let ignore_matcher = build_ignore_matcher(&common_ancestor);
let mut watcher = new_debouncer(Duration::from_secs(1), move |r| {
@@ -458,9 +465,9 @@ impl Rust {
})
.unwrap();
for path in watch_folders {
if !ignore_matcher.is_ignore(path, true) {
info!("Watching {} for changes...", display_path(path));
lookup(path, |file_type, p| {
if !ignore_matcher.is_ignore(&path, true) {
info!("Watching {} for changes...", display_path(&path));
lookup(&path, |file_type, p| {
if p != path {
debug!("Watching {} for changes...", display_path(&p));
let _ = watcher.watcher().watch(
@@ -690,7 +697,7 @@ impl AppSettings for RustAppSettings {
.expect("Cargo manifest must have the `package.name` field");
let out_dir = self
.out_dir(options.target.clone(), get_profile(options))
.out_dir(options.target.clone(), get_profile_dir(options).to_string())
.with_context(|| "failed to get project out directory")?;
let binary_extension: String = if self.target_triple.contains("windows") {
@@ -984,13 +991,20 @@ pub fn get_workspace_dir() -> crate::Result<PathBuf> {
)
}
pub fn get_profile(options: &Options) -> String {
pub fn get_profile(options: &Options) -> &str {
options
.args
.iter()
.position(|a| a == "--profile")
.map(|i| options.args[i + 1].clone())
.unwrap_or_else(|| if options.debug { "debug" } else { "release" }.into())
.map(|i| options.args[i + 1].as_str())
.unwrap_or_else(|| if options.debug { "debug" } else { "release" })
}
pub fn get_profile_dir(options: &Options) -> &str {
match get_profile(options) {
"dev" => "debug",
profile => profile,
}
}
#[allow(unused_variables)]
@@ -1099,6 +1113,9 @@ fn tauri_config_to_bundle_settings(
},
files: config.deb.files,
desktop_template: config.deb.desktop_template,
section: config.deb.section,
priority: config.deb.priority,
changelog: config.deb.changelog,
},
macos: MacOsSettings {
frameworks: config.macos.frameworks,

View File

@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use super::{get_profile, AppSettings, DevChild, ExitReason, Options, RustAppSettings, Target};
use super::{get_profile_dir, AppSettings, DevChild, ExitReason, Options, RustAppSettings, Target};
use crate::CommandExt;
use tauri_utils::display_path;
@@ -125,7 +125,7 @@ pub fn build(
options.target.replace(triple.into());
let triple_out_dir = app_settings
.out_dir(Some(triple.into()), get_profile(&options))
.out_dir(Some(triple.into()), get_profile_dir(&options).to_string())
.with_context(|| format!("failed to get {triple} out dir"))?;
build_production_app(options, available_targets, config_features.clone())

View File

@@ -177,6 +177,14 @@ where
Ok(())
}
pub fn kill_dev_app() -> Result<()> {
dev::DEV_CHILD
.get()
.map(|child| child.lock().unwrap().kill())
.unwrap_or(Ok(()))
.map_err(Into::into)
}
/// This maps the occurrence of `--verbose` flags to the correct log level
fn verbosity_level(num: u8) -> Level {
match num {