Compare commits

..

6 Commits

Author SHA1 Message Date
github-actions[bot]
d78fa20d86 Apply Version Updates From Current Changes (v1) (#9793)
Co-authored-by: amrbashir <amrbashir@users.noreply.github.com>
2024-05-15 20:09:07 +03:00
Amr Bashir
3b69c1384b Revert "fix(core/shell): speedup Command.execute & fix extra new lines (#9706)" (#9792)
* Revert "fix(core/shell): speedup `Command.execute` & fix extra new lines (#9706)"

This reverts commit 7f885bd5ed.

* change file
2024-05-15 19:28:15 +03:00
Amr Bashir
704260bb3c fix(macos/dialog): avoid setting empty default_path (#9784)
closes #7566

ref: https://github.com/tauri-apps/tauri/issues/4065
ref: https://github.com/tauri-apps/tauri/pull/4028
ref: https://github.com/tauri-apps/tauri/issues/9762
2024-05-15 18:45:11 +03:00
Amr Bashir
36b082a9c8 ci: pull .crate file from workspace target directory (#9732) 2024-05-10 02:32:15 +03:00
github-actions[bot]
f45d35cf06 Apply Version Updates From Current Changes (v1) (#9730)
Co-authored-by: amrbashir <amrbashir@users.noreply.github.com>
2024-05-10 00:13:21 +03:00
Amr Bashir
ef35a793c5 fix(core): fix compilation when shell-execute or shell-sidecar (#9729)
* fix(core): fix compilation when `shell-execute` or `shell-sidecar`

regression from: https://github.com/tauri-apps/tauri/pull/9706

* change file
2024-05-09 23:56:52 +03:00
19 changed files with 224 additions and 228 deletions

View File

@@ -72,7 +72,7 @@
],
"assets": [
{
"path": "${ pkg.path }/target/package/${ pkg.pkg }-${ pkgFile.version }.crate",
"path": "./target/package/${ pkg.pkg }-${ pkgFile.version }.crate",
"name": "${ pkg.pkg }-${ pkgFile.version }.crate"
}
]

2
Cargo.lock generated
View File

@@ -4021,7 +4021,7 @@ checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f"
[[package]]
name = "tauri"
version = "1.6.4"
version = "1.6.5"
dependencies = [
"anyhow",
"base64 0.21.7",

View File

@@ -1,5 +1,18 @@
# Changelog
## \[1.6.6]
### Bug Fixes
- [`704260bb3`](https://www.github.com/tauri-apps/tauri/commit/704260bb3c2bc54c149f2fe508bff09535b083ad)([#9784](https://www.github.com/tauri-apps/tauri/pull/9784)) Fix dialog crash on macOS when the `default_path` value is empty.
- [`3b69c1384`](https://www.github.com/tauri-apps/tauri/commit/3b69c1384bd089ad5dcff0c1b12fbfadeb585c6a)([#9792](https://www.github.com/tauri-apps/tauri/pull/9792)) Revert [#9706](https://github.com/tauri-apps/tauri/pull/9706) which broke compatability between `tauri` crate and the JS `@tauri-apps/api` npm package in a patch release where it should've been in a minor release.
## \[1.6.5]
### Bug Fixes
- [`ef35a793c`](https://www.github.com/tauri-apps/tauri/commit/ef35a793c5d923d55e338b51e04e6c280f7c810d)([#9729](https://www.github.com/tauri-apps/tauri/pull/9729)) Fix compilation error when `shell-execute` or `shell-sidecar` features are not active
## \[1.6.4]
### Enhancements

View File

@@ -10,7 +10,7 @@ license = "Apache-2.0 OR MIT"
name = "tauri"
readme = "README.md"
repository = "https://github.com/tauri-apps/tauri"
version = "1.6.4"
version = "1.6.6"
[package.metadata.docs.rs]
no-default-features = true

File diff suppressed because one or more lines are too long

View File

@@ -301,6 +301,10 @@ fn set_default_path(
mut dialog_builder: FileDialogBuilder,
default_path: PathBuf,
) -> FileDialogBuilder {
if default_path.as_os_str().is_empty() {
return dialog_builder;
}
// we need to adjust the separator on Windows: https://github.com/tauri-apps/tauri/issues/8074
let default_path: PathBuf = default_path.components().collect();
if default_path.is_file() || !default_path.exists() {

View File

@@ -8,7 +8,7 @@ use super::InvokeContext;
use crate::{api::ipc::CallbackFn, Runtime};
#[cfg(shell_scope)]
use crate::{Manager, Scopes};
use serde::{Deserialize, Serialize};
use serde::Deserialize;
use tauri_macros::{command_enum, module_command_handler, CommandModule};
#[cfg(shell_scope)]
@@ -63,15 +63,6 @@ pub struct CommandOptions {
#[derive(Deserialize, CommandModule)]
#[serde(tag = "cmd", rename_all = "camelCase")]
pub enum Cmd {
/// The execute and return script API.
#[cmd(shell_script, "shell > execute or shell > sidecar")]
#[serde(rename_all = "camelCase")]
ExecuteAndReturn {
program: String,
args: ExecuteArgs,
#[serde(default)]
options: CommandOptions,
},
/// The execute script API.
#[cmd(shell_script, "shell > execute or shell > sidecar")]
#[serde(rename_all = "camelCase")]
@@ -90,58 +81,9 @@ pub enum Cmd {
Open { path: String, with: Option<String> },
}
#[derive(Serialize)]
#[cfg(any(shell_execute, shell_sidecar))]
struct ChildProcessReturn {
code: Option<i32>,
signal: Option<i32>,
stdout: String,
stderr: String,
}
impl Cmd {
#[module_command_handler(shell_script)]
fn execute_and_return<R: Runtime>(
context: InvokeContext<R>,
program: String,
args: ExecuteArgs,
options: CommandOptions,
) -> super::Result<ChildProcessReturn> {
let encoding = options
.encoding
.as_ref()
.and_then(|encoding| crate::api::process::Encoding::for_label(encoding.as_bytes()));
let command = prepare_cmd(&context, &program, args, options)?;
let mut command: std::process::Command = command.into();
let output = command.output()?;
let (stdout, stderr) = match encoding {
Some(encoding) => (
encoding.decode_with_bom_removal(&output.stdout).0.into(),
encoding.decode_with_bom_removal(&output.stderr).0.into(),
),
None => (
String::from_utf8(output.stdout)?,
String::from_utf8(output.stderr)?,
),
};
#[cfg(unix)]
use std::os::unix::process::ExitStatusExt;
Ok(ChildProcessReturn {
code: output.status.code(),
#[cfg(windows)]
signal: None,
#[cfg(unix)]
signal: output.status.signal(),
stdout,
stderr,
})
}
#[module_command_handler(shell_script)]
#[allow(unused_variables)]
fn execute<R: Runtime>(
context: InvokeContext<R>,
program: String,
@@ -149,29 +91,91 @@ impl Cmd {
on_event_fn: CallbackFn,
options: CommandOptions,
) -> super::Result<ChildId> {
use std::future::Future;
use std::pin::Pin;
let command = prepare_cmd(&context, &program, args, options)?;
let (mut rx, child) = command.spawn()?;
let pid = child.pid();
command_child_store().lock().unwrap().insert(pid, child);
crate::async_runtime::spawn(async move {
while let Some(event) = rx.recv().await {
if matches!(event, crate::api::process::CommandEvent::Terminated(_)) {
command_child_store().lock().unwrap().remove(&pid);
let mut command = if options.sidecar {
#[cfg(not(shell_sidecar))]
return Err(crate::Error::ApiNotAllowlisted("shell > sidecar".to_string()).into_anyhow());
#[cfg(shell_sidecar)]
{
let program = PathBuf::from(program);
let program_as_string = program.display().to_string();
let program_no_ext_as_string = program.with_extension("").display().to_string();
let configured_sidecar = context
.config
.tauri
.bundle
.external_bin
.as_ref()
.map(|bins| {
bins
.iter()
.find(|b| b == &&program_as_string || b == &&program_no_ext_as_string)
})
.unwrap_or_default();
if let Some(sidecar) = configured_sidecar {
context
.window
.state::<Scopes>()
.shell
.prepare_sidecar(&program.to_string_lossy(), sidecar, args)
.map_err(crate::error::into_anyhow)?
} else {
return Err(crate::Error::SidecarNotAllowed(program).into_anyhow());
}
let js = crate::api::ipc::format_callback(on_event_fn, &event)
.expect("unable to serialize CommandEvent");
let _ = context.window.eval(js.as_str());
}
});
} else {
#[cfg(not(shell_execute))]
return Err(crate::Error::ApiNotAllowlisted("shell > execute".to_string()).into_anyhow());
#[cfg(shell_execute)]
match context
.window
.state::<Scopes>()
.shell
.prepare(&program, args)
{
Ok(cmd) => cmd,
Err(e) => {
#[cfg(debug_assertions)]
eprintln!("{e}");
return Err(crate::Error::ProgramNotAllowed(PathBuf::from(program)).into_anyhow());
}
}
};
#[cfg(any(shell_execute, shell_sidecar))]
{
if let Some(cwd) = options.cwd {
command = command.current_dir(cwd);
}
if let Some(env) = options.env {
command = command.envs(env);
} else {
command = command.env_clear();
}
if let Some(encoding) = options.encoding {
if let Some(encoding) = crate::api::process::Encoding::for_label(encoding.as_bytes()) {
command = command.encoding(encoding);
} else {
return Err(anyhow::anyhow!(format!("unknown encoding {encoding}")));
}
}
let (mut rx, child) = command.spawn()?;
Ok(pid)
let pid = child.pid();
command_child_store().lock().unwrap().insert(pid, child);
crate::async_runtime::spawn(async move {
while let Some(event) = rx.recv().await {
if matches!(event, crate::api::process::CommandEvent::Terminated(_)) {
command_child_store().lock().unwrap().remove(&pid);
}
let js = crate::api::ipc::format_callback(on_event_fn, &event)
.expect("unable to serialize CommandEvent");
let _ = context.window.eval(js.as_str());
}
});
Ok(pid)
}
}
#[module_command_handler(shell_script)]
@@ -222,81 +226,6 @@ impl Cmd {
}
}
fn prepare_cmd<R: Runtime>(
context: &InvokeContext<R>,
program: &String,
args: ExecuteArgs,
options: CommandOptions,
) -> super::Result<crate::api::process::Command> {
let mut command = if options.sidecar {
#[cfg(not(shell_sidecar))]
return Err(crate::Error::ApiNotAllowlisted("shell > sidecar".to_string()).into_anyhow());
#[cfg(shell_sidecar)]
{
let program = PathBuf::from(program);
let program_as_string = program.display().to_string();
let program_no_ext_as_string = program.with_extension("").display().to_string();
let configured_sidecar = context
.config
.tauri
.bundle
.external_bin
.as_ref()
.map(|bins| {
bins
.iter()
.find(|b| b == &&program_as_string || b == &&program_no_ext_as_string)
})
.unwrap_or_default();
if let Some(sidecar) = configured_sidecar {
context
.window
.state::<Scopes>()
.shell
.prepare_sidecar(&program.to_string_lossy(), sidecar, args)
.map_err(crate::error::into_anyhow)
} else {
Err(crate::Error::SidecarNotAllowed(program).into_anyhow())
}
}
} else {
#[cfg(not(shell_execute))]
return Err(crate::Error::ApiNotAllowlisted("shell > execute".to_string()).into_anyhow());
#[cfg(shell_execute)]
match context
.window
.state::<Scopes>()
.shell
.prepare(program, args)
{
Ok(cmd) => Ok(cmd),
Err(e) => {
#[cfg(debug_assertions)]
eprintln!("{e}");
Err(crate::Error::ProgramNotAllowed(PathBuf::from(program)).into_anyhow())
}
}
}?;
if let Some(cwd) = options.cwd {
command = command.current_dir(cwd);
}
if let Some(env) = options.env {
command = command.envs(env);
} else {
command = command.env_clear();
}
if let Some(encoding) = &options.encoding {
if let Some(encoding) = crate::api::process::Encoding::for_label(encoding.as_bytes()) {
command = command.encoding(encoding);
} else {
return Err(anyhow::anyhow!(format!("unknown encoding {encoding}")));
}
}
Ok(command)
}
#[cfg(test)]
mod tests {
use super::{Buffer, ChildId, CommandOptions, ExecuteArgs};

View File

@@ -1,5 +1,11 @@
# Changelog
## \[1.5.6]
### Bug Fixes
- [`3b69c1384`](https://www.github.com/tauri-apps/tauri/commit/3b69c1384bd089ad5dcff0c1b12fbfadeb585c6a)([#9792](https://www.github.com/tauri-apps/tauri/pull/9792)) Revert [#9706](https://github.com/tauri-apps/tauri/pull/9706) which broke compatability between `tauri` crate and the JS `@tauri-apps/api` npm package in a patch release where it should've been in a minor release.
## \[1.5.5]
### Enhancements

View File

@@ -1,6 +1,6 @@
{
"name": "@tauri-apps/api",
"version": "1.5.5",
"version": "1.5.6",
"description": "Tauri API definitions",
"funding": {
"type": "opencollective",

View File

@@ -115,6 +115,38 @@ interface ChildProcess {
stderr: string
}
/**
* Spawns a process.
*
* @ignore
* @param program The name of the scoped command.
* @param onEvent Event handler.
* @param args Program arguments.
* @param options Configuration for the process spawn.
* @returns A promise resolving to the process id.
*/
async function execute(
onEvent: (event: CommandEvent) => void,
program: string,
args: string | string[] = [],
options?: InternalSpawnOptions
): Promise<number> {
if (typeof args === 'object') {
Object.freeze(args)
}
return invokeTauriCommand<number>({
__tauriModule: 'Shell',
message: {
cmd: 'execute',
program,
args,
options,
onEventFn: transformCallback(onEvent)
}
})
}
/**
* @since 1.0.0
*/
@@ -417,41 +449,27 @@ class Command extends EventEmitter<'close' | 'error'> {
* @returns A promise resolving to the child process handle.
*/
async spawn(): Promise<Child> {
const program = this.program
const args = this.args
const options = this.options
if (typeof args === 'object') {
Object.freeze(args)
}
const onEvent = (event: CommandEvent) => {
switch (event.event) {
case 'Error':
this.emit('error', event.payload)
break
case 'Terminated':
this.emit('close', event.payload)
break
case 'Stdout':
this.stdout.emit('data', event.payload)
break
case 'Stderr':
this.stderr.emit('data', event.payload)
break
}
}
return invokeTauriCommand<number>({
__tauriModule: 'Shell',
message: {
cmd: 'execute',
program,
args,
options,
onEventFn: transformCallback(onEvent)
}
}).then((pid) => new Child(pid))
return execute(
(event) => {
switch (event.event) {
case 'Error':
this.emit('error', event.payload)
break
case 'Terminated':
this.emit('close', event.payload)
break
case 'Stdout':
this.stdout.emit('data', event.payload)
break
case 'Stderr':
this.stderr.emit('data', event.payload)
break
}
},
this.program,
this.args,
this.options
).then((pid) => new Child(pid))
}
/**
@@ -469,22 +487,25 @@ class Command extends EventEmitter<'close' | 'error'> {
* @returns A promise resolving to the child process output.
*/
async execute(): Promise<ChildProcess> {
const program = this.program
const args = this.args
const options = this.options
if (typeof args === 'object') {
Object.freeze(args)
}
return invokeTauriCommand<ChildProcess>({
__tauriModule: 'Shell',
message: {
cmd: 'executeAndReturn',
program,
args,
options
}
return new Promise((resolve, reject) => {
this.on('error', reject)
const stdout: string[] = []
const stderr: string[] = []
this.stdout.on('data', (line: string) => {
stdout.push(line)
})
this.stderr.on('data', (line: string) => {
stderr.push(line)
})
this.on('close', (payload: TerminatedPayload) => {
resolve({
code: payload.code,
signal: payload.signal,
stdout: stdout.join('\n'),
stderr: stderr.join('\n')
})
})
this.spawn().catch(reject)
})
}
}

View File

@@ -3,6 +3,6 @@
"version": "1.5.14",
"node": ">= 10.0.0"
},
"tauri": "1.6.4",
"tauri": "1.6.6",
"tauri-build": "1.5.2"
}

View File

@@ -1,5 +1,11 @@
# Changelog
## \[0.1.4]
### New Features
- [`435d7513`](https://www.github.com/tauri-apps/tauri/commit/435d7513e45eab8b512e9a7e695a1adef8a98a46)([#8609](https://www.github.com/tauri-apps/tauri/pull/8609)) Added `webviewOptions` object to the `tauri:options` capability to configure the [Edge webview options](https://learn.microsoft.com/en-us/microsoft-edge/webdriver-chromium/capabilities-edge-options#webviewoptions-object) on Windows.
## \[0.1.3]
### What's Changed

View File

@@ -234,9 +234,9 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
[[package]]
name = "libc"
version = "0.2.147"
version = "0.2.153"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
[[package]]
name = "memchr"
@@ -255,9 +255,9 @@ dependencies = [
[[package]]
name = "mio"
version = "0.8.8"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
dependencies = [
"libc",
"wasi",
@@ -421,7 +421,7 @@ dependencies = [
[[package]]
name = "tauri-driver"
version = "0.1.3"
version = "0.1.4"
dependencies = [
"anyhow",
"futures",

View File

@@ -2,7 +2,7 @@ workspace = { }
[package]
name = "tauri-driver"
version = "0.1.3"
version = "0.1.4"
authors = [ "Tauri Programme within The Commons Conservancy" ]
categories = [ "gui", "web-programming" ]
license = "Apache-2.0 OR MIT"

View File

@@ -9,13 +9,15 @@ native WebDriver server for you behind the scenes. It requires two separate
ports to be used since two distinct [WebDriver Remote Ends] run.
You can configure the ports used with arguments when starting the binary:
* `--port` (default: `4444`)
* `--native-port` (default: `4445`)
- `--port` (default: `4444`)
- `--native-port` (default: `4445`)
Supported platforms:
* **[pre-alpha]** Linux w/ `WebKitWebDriver`
* **[pre-alpha]** Windows w/ [Microsoft Edge Driver]
* **[Todo]** macOS w/ [Appium Mac2 Driver] (probably)
- **[pre-alpha]** Linux w/ `WebKitWebDriver`
- **[pre-alpha]** Windows w/ [Microsoft Edge Driver]
- **[Todo]** macOS w/ [Appium Mac2 Driver] (probably)
_note: the (probably) items haven't been proof-of-concept'd yet, and if it is
not possible to use the listed native webdriver, then a custom implementation

View File

@@ -1,4 +1,4 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

View File

@@ -1,7 +1,18 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
//! [![](https://github.com/tauri-apps/tauri/raw/dev/.github/splash.png)](https://tauri.app)
//!
//! Cross-platform WebDriver server for Tauri applications.
//!
//! This is a [WebDriver Intermediary Node](https://www.w3.org/TR/webdriver/#dfn-intermediary-nodes) that wraps the native WebDriver server for platforms that [Tauri](https://github.com/tauri-apps/tauri) supports. Your WebDriver client will connect to the running `tauri-driver` server, and `tauri-driver` will handle starting the native WebDriver server for you behind the scenes. It requires two separate ports to be used since two distinct [WebDriver Remote Ends](https://www.w3.org/TR/webdriver/#dfn-remote-ends) run.
#![doc(
html_logo_url = "https://github.com/tauri-apps/tauri/raw/dev/app-icon.png",
html_favicon_url = "https://github.com/tauri-apps/tauri/raw/dev/app-icon.png"
)]
mod cli;
mod server;
mod webdriver;

View File

@@ -1,4 +1,4 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
@@ -20,10 +20,14 @@ type HttpClient = Client<hyper::client::HttpConnector>;
const TAURI_OPTIONS: &str = "tauri:options";
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct TauriOptions {
application: PathBuf,
#[serde(default)]
args: Vec<String>,
#[cfg(target_os = "windows")]
#[serde(default)]
webview_options: Option<Value>,
}
impl TauriOptions {
@@ -44,7 +48,7 @@ impl TauriOptions {
map.insert("browserName".into(), json!("webview2"));
map.insert(
"ms:edgeOptions".into(),
json!({"binary": self.application, "args": self.args}),
json!({"binary": self.application, "args": self.args, "webviewOptions": self.webview_options}),
);
map
}

View File

@@ -1,4 +1,4 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT