Skip to content

Commit

Permalink
Revert "fix(core/shell): speedup Command.execute & fix extra new li…
Browse files Browse the repository at this point in the history
…nes (#9706)" (#9792)

* Revert "fix(core/shell): speedup `Command.execute` & fix extra new lines (#9706)"

This reverts commit 7f885bd.

* change file
  • Loading branch information
amrbashir authored May 15, 2024
1 parent 704260b commit 3b69c13
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 207 deletions.
6 changes: 6 additions & 0 deletions .changes/revert-9706.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"tauri": "patch:bug"
"@tauri-apps/api": "patch:bug"
---

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.
2 changes: 1 addition & 1 deletion core/tauri/scripts/bundle.global.js

Large diffs are not rendered by default.

237 changes: 82 additions & 155 deletions core/tauri/src/endpoints/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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")]
Expand All @@ -90,89 +81,101 @@ 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| encoding_rs::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,
args: ExecuteArgs,
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 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());
}
}
} 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()?;

let (mut rx, child) = command.spawn()?;
let pid = child.pid();
command_child_store().lock().unwrap().insert(pid, child);

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");

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 _ = context.window.eval(js.as_str());
}
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)
Ok(pid)
}
}

#[module_command_handler(shell_script)]
Expand Down Expand Up @@ -223,82 +226,6 @@ impl Cmd {
}
}

#[cfg(any(shell_execute, shell_sidecar))]
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) = encoding_rs::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};
Expand Down
Loading

0 comments on commit 3b69c13

Please sign in to comment.