Prechádzať zdrojové kódy

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 7f885bd5edf3e179ddf0b674c3ea7a96e26ce39e.

* change file
Amr Bashir 1 rok pred
rodič
commit
3b69c1384b

+ 6 - 0
.changes/revert-9706.md

@@ -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.

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 0 - 0
core/tauri/scripts/bundle.global.js


+ 82 - 155
core/tauri/src/endpoints/shell.rs

@@ -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,59 +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| 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,
@@ -150,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 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)]
@@ -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};

+ 72 - 51
tooling/api/src/shell.ts

@@ -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)
     })
   }
 }

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov