diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-06-24 21:38:53 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-06-24 21:40:49 +0900 |
| commit | 7f810b1bb288445ee5376fada752e84ecb1ce211 (patch) | |
| tree | 631ec748f14757d314baba704c6c175183ed096a | |
| parent | a8f115666344abe3b606a4a65595ca301e7ac08a (diff) | |
| download | php-shirabe-7f810b1bb288445ee5376fada752e84ecb1ce211.tar.gz php-shirabe-7f810b1bb288445ee5376fada752e84ecb1ce211.tar.zst php-shirabe-7f810b1bb288445ee5376fada752e84ecb1ce211.zip | |
feat(process): wire execute output handling to a callback model
Replace the Option<&mut PhpMixed> output plumbing with the IntoExecOutput
trait modelling each PHP `$output` case (forward, capture-to-buffer,
discard, callback). This lets do_execute pass a real output handler to
Process::run, captures output back via get_output, and lets Svn pass its
streaming filter handler through execute instead of skipping it.
| -rw-r--r-- | crates/shirabe/src/downloader/gzip_downloader.rs | 2 | ||||
| -rw-r--r-- | crates/shirabe/src/downloader/rar_downloader.rs | 2 | ||||
| -rw-r--r-- | crates/shirabe/src/downloader/xz_downloader.rs | 2 | ||||
| -rw-r--r-- | crates/shirabe/src/event_dispatcher/event_dispatcher.rs | 4 | ||||
| -rw-r--r-- | crates/shirabe/src/package/locker.rs | 4 | ||||
| -rw-r--r-- | crates/shirabe/src/platform/hhvm_detector.rs | 2 | ||||
| -rw-r--r-- | crates/shirabe/src/repository/path_repository.rs | 10 | ||||
| -rw-r--r-- | crates/shirabe/src/util/bitbucket.rs | 2 | ||||
| -rw-r--r-- | crates/shirabe/src/util/filesystem.rs | 2 | ||||
| -rw-r--r-- | crates/shirabe/src/util/process_executor.rs | 251 | ||||
| -rw-r--r-- | crates/shirabe/src/util/svn.rs | 50 | ||||
| -rw-r--r-- | crates/shirabe/tests/platform/hhvm_detector_test.rs | 4 | ||||
| -rw-r--r-- | crates/shirabe/tests/util/process_executor_test.rs | 2 |
13 files changed, 177 insertions, 160 deletions
diff --git a/crates/shirabe/src/downloader/gzip_downloader.rs b/crates/shirabe/src/downloader/gzip_downloader.rs index 8146145..b7b92c6 100644 --- a/crates/shirabe/src/downloader/gzip_downloader.rs +++ b/crates/shirabe/src/downloader/gzip_downloader.rs @@ -119,7 +119,7 @@ impl ArchiveDownloader for GzipDownloader { .map(|s| PhpMixed::String(s.clone())) .collect(), ), - Some(&mut process_output), + &mut process_output, None, )? == 0 { diff --git a/crates/shirabe/src/downloader/rar_downloader.rs b/crates/shirabe/src/downloader/rar_downloader.rs index 73d5fdf..88183f9 100644 --- a/crates/shirabe/src/downloader/rar_downloader.rs +++ b/crates/shirabe/src/downloader/rar_downloader.rs @@ -92,7 +92,7 @@ impl ArchiveDownloader for RarDownloader { .map(|s| PhpMixed::String(s.clone())) .collect(), ), - Some(&mut process_output), + &mut process_output, None, )? == 0 { diff --git a/crates/shirabe/src/downloader/xz_downloader.rs b/crates/shirabe/src/downloader/xz_downloader.rs index d7f94c3..3e61ba5 100644 --- a/crates/shirabe/src/downloader/xz_downloader.rs +++ b/crates/shirabe/src/downloader/xz_downloader.rs @@ -79,7 +79,7 @@ impl ArchiveDownloader for XzDownloader { .map(|s| PhpMixed::String(s.to_string())) .collect(), ), - Some(&mut ignored_output), + &mut ignored_output, None, )? == 0 { diff --git a/crates/shirabe/src/event_dispatcher/event_dispatcher.rs b/crates/shirabe/src/event_dispatcher/event_dispatcher.rs index acc3138..3ef27f8 100644 --- a/crates/shirabe/src/event_dispatcher/event_dispatcher.rs +++ b/crates/shirabe/src/event_dispatcher/event_dispatcher.rs @@ -785,7 +785,9 @@ impl EventDispatcher { return self.process.borrow_mut().execute_tty(exec, None); } - self.process.borrow_mut().execute(exec, (), None) + self.process + .borrow_mut() + .execute(exec, ProcessExecutor::FORWARD_OUTPUT, None) } fn get_php_exec_command(&self) -> anyhow::Result<String> { diff --git a/crates/shirabe/src/package/locker.rs b/crates/shirabe/src/package/locker.rs index a034497..8e6f3fb 100644 --- a/crates/shirabe/src/package/locker.rs +++ b/crates/shirabe/src/package/locker.rs @@ -833,7 +833,7 @@ impl Locker { let mut output = PhpMixed::Null; if 0 == self.process.borrow_mut().execute( PhpMixed::List(command.into_iter().map(PhpMixed::String).collect()), - Some(&mut output), + &mut output, path.as_deref(), )? { let output_str = trim( @@ -860,7 +860,7 @@ impl Locker { PhpMixed::String("-r".to_string()), PhpMixed::String(source_ref.clone()), ]), - Some(&mut output), + &mut output, path.as_deref(), )? { let mut m: IndexMap<CaptureKey, String> = IndexMap::new(); diff --git a/crates/shirabe/src/platform/hhvm_detector.rs b/crates/shirabe/src/platform/hhvm_detector.rs index 152e29a..da062d5 100644 --- a/crates/shirabe/src/platform/hhvm_detector.rs +++ b/crates/shirabe/src/platform/hhvm_detector.rs @@ -69,7 +69,7 @@ impl HhvmDetector { ); let exit_code = executor .borrow_mut() - .execute(cmd, Some(&mut version_output), None) + .execute(cmd, &mut version_output, None) .unwrap_or(1); if exit_code == 0 { *cache = Some(version_output.as_string().map(|s| s.to_string())); diff --git a/crates/shirabe/src/repository/path_repository.rs b/crates/shirabe/src/repository/path_repository.rs index 1a4cf6f..2f99ceb 100644 --- a/crates/shirabe/src/repository/path_repository.rs +++ b/crates/shirabe/src/repository/path_repository.rs @@ -250,12 +250,12 @@ impl PathRepository { let code1 = self .process .borrow_mut() - .execute(cmd.clone(), Some(&mut ref1), Some(path.as_str())) + .execute(cmd.clone(), &mut ref1, Some(path.as_str())) .unwrap_or(1); let code2 = self .process .borrow_mut() - .execute(cmd, Some(&mut ref2), None) + .execute(cmd, &mut ref2, None) .unwrap_or(1); if code1 == 0 && code2 == 0 && ref1.as_string() == ref2.as_string() { package.insert( @@ -280,11 +280,7 @@ impl PathRepository { && self .process .borrow_mut() - .execute( - PhpMixed::from(command), - Some(&mut output), - Some(path.as_str()), - ) + .execute(PhpMixed::from(command), &mut output, Some(path.as_str())) .unwrap_or(1) == 0 { diff --git a/crates/shirabe/src/util/bitbucket.rs b/crates/shirabe/src/util/bitbucket.rs index 3fc698b..9c8d59b 100644 --- a/crates/shirabe/src/util/bitbucket.rs +++ b/crates/shirabe/src/util/bitbucket.rs @@ -82,7 +82,7 @@ impl Bitbucket { .borrow_mut() .execute( PhpMixed::from(vec!["git", "config", "bitbucket.accesstoken"]), - Some(&mut output), + &mut output, None, ) .unwrap_or(1) diff --git a/crates/shirabe/src/util/filesystem.rs b/crates/shirabe/src/util/filesystem.rs index 6510638..ec1e65a 100644 --- a/crates/shirabe/src/util/filesystem.rs +++ b/crates/shirabe/src/util/filesystem.rs @@ -120,7 +120,7 @@ impl Filesystem { .get_process() .execute( PhpMixed::List(cmd.iter().map(|s| PhpMixed::String(s.clone())).collect()), - Some(&mut output), + &mut output, None, ) .map(|n| n == 0) diff --git a/crates/shirabe/src/util/process_executor.rs b/crates/shirabe/src/util/process_executor.rs index 842e934..609fd70 100644 --- a/crates/shirabe/src/util/process_executor.rs +++ b/crates/shirabe/src/util/process_executor.rs @@ -13,9 +13,9 @@ use shirabe_external_packages::symfony::process::exception::ProcessSignaledExcep use shirabe_external_packages::symfony::process::exception::RuntimeException as SymfonyProcessRuntimeException; use shirabe_php_shim::{ LogicException, PhpMixed, RuntimeException, array_intersect, array_map, call_user_func, - defined, escapeshellarg, explode, implode, in_array, is_array, is_callable, is_dir, is_numeric, - is_string, rtrim, sprintf, str_replace, strcspn, strlen, strpbrk, strtolower, strtr_array, - substr_replace, trim, usleep, + defined, escapeshellarg, explode, implode, in_array, is_array, is_dir, is_numeric, is_string, + rtrim, sprintf, str_replace, strcspn, strlen, strpbrk, strtolower, strtr_array, substr_replace, + trim, usleep, }; use crate::io::IOInterface; @@ -69,7 +69,14 @@ impl std::fmt::Debug for Job { } } +/// Output target marking the "no `$output` argument" case of `ProcessExecutor::execute`, where the +/// child's output is forwarded to STDOUT/STDERR (or the IO) instead of captured. Use the +/// [`ProcessExecutor::FORWARD_OUTPUT`] constant rather than constructing this directly. +pub struct ProcessForwardOutput; + impl ProcessExecutor { + pub const FORWARD_OUTPUT: ProcessForwardOutput = ProcessForwardOutput; + const STATUS_QUEUED: i64 = 1; const STATUS_STARTED: i64 = 2; const STATUS_COMPLETED: i64 = 3; @@ -104,30 +111,13 @@ impl ProcessExecutor { } /// runs a process on the commandline - /// - /// @param string|non-empty-list<string> $command the command to execute - /// @param mixed $output the output will be written into this var if passed by ref - /// if a callable is passed it will be used as output handler - /// @param null|string $cwd the working directory - /// @return int statuscode pub fn execute<'o, C, O>(&mut self, command: C, output: O, cwd: Option<&str>) -> Result<i64> where C: IntoExecCommand, O: IntoExecOutput<'o>, { let command = command.into_exec_command(); - let mut output = output.into_exec_output(); - // PHP: func_num_args() > 1 - let has_output_arg = output.has_output(); - let rc = if has_output_arg { - let mut buf = PhpMixed::Null; - let result = self.do_execute(command, cwd, false, Some(&mut buf))?; - output.write_back(buf); - result - } else { - self.do_execute(command, cwd, false, None)? - }; - Ok(rc) + self.do_execute(command, cwd, false, output) } /// Convenience wrapper used by phase-A code that calls @@ -146,7 +136,7 @@ impl ProcessExecutor { .collect(), ); let mut buf = PhpMixed::String(String::new()); - let rc = self.execute(cmd, Some(&mut buf), cwd).unwrap_or(1); + let rc = self.execute(cmd, &mut buf, cwd).unwrap_or(1); *output = buf.as_string().unwrap_or("").to_string(); rc } @@ -158,22 +148,23 @@ impl ProcessExecutor { { let command = command.into_exec_command(); if Platform::is_tty(None) { - return self.do_execute(command, cwd, true, None); + return self.do_execute(command, cwd, true, Self::FORWARD_OUTPUT); } - self.do_execute(command, cwd, false, None) + self.do_execute(command, cwd, false, Self::FORWARD_OUTPUT) } - /// @param string|non-empty-list<string> $command - /// @param array<string, string>|null $env - fn run_process( + fn run_process<'o, O>( &mut self, command: PhpMixed, cwd: Option<&str>, env: Option<IndexMap<String, String>>, tty: bool, - mut output: Option<&mut PhpMixed>, - ) -> Result<Option<i64>> { + mut output: O, + ) -> Result<Option<i64>> + where + O: IntoExecOutput<'o>, + { // On Windows, we don't rely on the OS to find the executable if possible to avoid lookups // in the current directory which could be untrusted. Instead we use the ExecutableFinder. @@ -235,21 +226,6 @@ impl ProcessExecutor { // ignore TTY enabling errors } - // PHP: $callback = is_callable($output) ? $output : fn($type, $buffer) => $this->outputHandler($type, $buffer); - let output_is_callable = output.as_deref().map(is_callable).unwrap_or(false); - let _callback: Box<dyn Fn(&str, &str)> = if output_is_callable { - // TODO(phase-c): the user-supplied $output is a PhpMixed callable that cannot be - // invoked without a typed callable model (Rc<dyn Fn>); deferred with the callable model. - Box::new(|_t: &str, _b: &str| {}) - } else { - // TODO(phase-c): the fallback must call self.output_handler(type, buffer) (which is - // &mut self and writes to io / updates last_message), but this is a 'static - // `Box<dyn Fn>` that cannot borrow &mut self. Wiring it needs the handler state shared - // (Rc<RefCell<...>>). The callback is also not yet passed to process.run, whose Symfony - // Process backing stays todo!(). - Box::new(|_t: &str, _b: &str| {}) - }; - let io_for_signal = self.io.clone(); let signal_handler = SignalHandler::create( vec![ @@ -268,17 +244,22 @@ impl ProcessExecutor { ); let result: Result<()> = (|| -> Result<()> { - process.run( - /* callback */ Some(Box::new(|_t: &str, _b: &str| false)), - IndexMap::new(), - )?; - - let output_is_callable_inner = output.as_deref().map(is_callable).unwrap_or(false); - if self.capture_output - && !output_is_callable_inner - && let Some(out) = output.as_mut() - { - **out = PhpMixed::String(process.get_output()?); + match output.to_callback() { + Ok(callback) => { + process.run(Some(callback), IndexMap::new())?; + } + Err(mut output) => { + let capture_output = self.capture_output; + let mut io = self.io.clone(); + let mut callback = move |r#type: &str, buffer: &str| { + Self::output_handler(capture_output, &mut io, r#type, buffer); + false + }; + process.run(Some(Box::new(callback)), IndexMap::new())?; + if self.capture_output { + output.write_back(process.get_output()?); + } + } } self.error_output = process.get_error_output()?; @@ -306,18 +287,19 @@ impl ProcessExecutor { Ok(process.get_exit_code()) } - /// @param string|non-empty-list<string> $command - /// @param mixed $output - fn do_execute( + fn do_execute<'o, O>( &mut self, command: PhpMixed, cwd: Option<&str>, tty: bool, - mut output: Option<&mut PhpMixed>, - ) -> Result<i64> { + output: O, + ) -> Result<i64> + where + O: IntoExecOutput<'o>, + { self.output_command_run(&command, cwd, false); - self.capture_output = output.is_some(); + self.capture_output = output.capture_output(); self.error_output = String::new(); let mut env: Option<IndexMap<String, String>> = None; @@ -338,7 +320,7 @@ impl ProcessExecutor { cwd, Some(git_env.clone()), tty, - Some(&mut config_value), + &mut config_value, )?; let trimmed = trim(config_value.as_string().unwrap_or(""), None); if trimmed == "explicit" { @@ -400,25 +382,28 @@ impl ProcessExecutor { } } - fn output_handler(&mut self, r#type: &str, buffer: &str) { - if self.capture_output { + fn output_handler( + capture_output: bool, + io: &mut Option<std::rc::Rc<std::cell::RefCell<dyn IOInterface>>>, + r#type: &str, + buffer: &str, + ) { + if capture_output { return; } - if self.io.is_none() { + if io.is_none() { print!("{}", buffer); return; } if Process::ERR == r#type { - self.io - .as_mut() + io.as_mut() .unwrap() .write_error_raw3(buffer, false, io_interface::NORMAL); } else { - self.io - .as_mut() + io.as_mut() .unwrap() .write_raw3(buffer, false, io_interface::NORMAL); } @@ -892,73 +877,113 @@ impl IntoExecCommand for &[String] { } } -/// Phase B helper trait: write captured output back to the caller's buffer. -pub trait IntoExecOutput<'a> { - type Sink: ExecOutputSink + 'a; - fn into_exec_output(self) -> Self::Sink; -} +/// Models the `mixed &$output` parameter of `ProcessExecutor::execute` (cf. +/// `composer/src/Composer/Util/ProcessExecutor.php`). In PHP the behaviour is selected by +/// `func_num_args()` and `is_callable($output)`; here each behaviour is a distinct implementing type: +/// +/// | PHP call site | meaning | implementor | `capture_output` | +/// |---|---|---|---| +/// | `execute($cmd)` | forward child output to STDOUT/STDERR (or the IO) | [`ProcessForwardOutput`] | `false` | +/// | `execute($cmd, $out)` | assign captured output back to `$out` | `&mut String` / `&mut PhpMixed` | `true` | +/// | `execute($cmd, $out)` where `$out` is unused | capture (suppress output) but discard it | `()` | `true` | +/// | `execute($cmd, $cb)` | drive the child through the callback | `Box<dyn FnMut(&str, &str) -> bool>` | `false` | +/// +/// `capture_output` maps to PHP's `$this->captureOutput` (`func_num_args() > 3` in `doExecute`): when +/// `true`, `outputHandler` swallows the child output instead of echoing it, and the full output is +/// read back via `Process::getOutput()` afterwards. +pub trait IntoExecOutput<'a>: Sized { + /// Whether the child's output is captured rather than forwarded to the terminal/IO. + /// + /// Mirrors `$this->captureOutput`: `true` makes `output_handler` swallow the stream so the buffer + /// can be retrieved via `Process::get_output` (and handed to [`write_back`](Self::write_back)), + /// `false` lets it pass through to STDOUT/STDERR or the IO. + fn capture_output(&self) -> bool; + + /// Splits the output target into the two PHP cases handled by `is_callable($output)`: + /// `Ok(callback)` for a user-supplied output handler (passed straight to `Process::run`), + /// `Err(self)` for the capture/forward cases (a default handler is used and `self` is returned + /// so the captured output can still be written back). + fn to_callback(self) -> Result<Box<dyn FnMut(&str, &str) -> bool>, Self>; -pub trait ExecOutputSink { - fn has_output(&self) -> bool; - fn write_back(&mut self, value: PhpMixed); + /// Assigns the captured output back to the by-reference target, mirroring PHP's + /// `$output = $process->getOutput()`. Only meaningful when [`capture_output`](Self::capture_output) + /// is `true`; a no-op for the forwarding and discarding variants. + fn write_back(&mut self, value: String); } -pub struct NoOutput; -impl ExecOutputSink for NoOutput { - fn has_output(&self) -> bool { - false +/// `execute($cmd, $out)` where the caller never reads `$out` (e.g. `HomeCommand::openBrowser`): +/// output is captured (so the terminal stays quiet) but thrown away. +impl<'a> IntoExecOutput<'a> for () { + fn capture_output(&self) -> bool { + true + } + + fn to_callback(self) -> Result<Box<dyn FnMut(&str, &str) -> bool>, Self> { + Err(self) } - fn write_back(&mut self, _value: PhpMixed) {} + + fn write_back(&mut self, _value: String) {} } -pub struct PhpMixedOutput<'a>(Option<&'a mut PhpMixed>); -impl<'a> ExecOutputSink for PhpMixedOutput<'a> { - fn has_output(&self) -> bool { - self.0.is_some() +/// `execute($cmd)` with no output argument: the child's output is forwarded to STDOUT/STDERR +/// (or the IO). Obtained via [`ProcessExecutor::FORWARD_OUTPUT`]. +impl<'a> IntoExecOutput<'a> for ProcessForwardOutput { + fn capture_output(&self) -> bool { + false } - fn write_back(&mut self, value: PhpMixed) { - if let Some(out) = self.0.as_deref_mut() { - *out = value; - } + + fn to_callback(self) -> Result<Box<dyn FnMut(&str, &str) -> bool>, Self> { + Err(self) } + + fn write_back(&mut self, _value: String) {} } -pub struct StringOutput<'a>(&'a mut String); -impl<'a> ExecOutputSink for StringOutput<'a> { - fn has_output(&self) -> bool { +/// `execute($cmd, $out)` where `$out` holds a `mixed`/string value: output is captured and assigned +/// back as a [`PhpMixed::String`]. +impl<'a> IntoExecOutput<'a> for &'a mut PhpMixed { + fn capture_output(&self) -> bool { true } - fn write_back(&mut self, value: PhpMixed) { - *self.0 = value.as_string().unwrap_or("").to_string(); + + fn to_callback(self) -> Result<Box<dyn FnMut(&str, &str) -> bool>, Self> { + Err(self) } -} -impl<'a> IntoExecOutput<'a> for () { - type Sink = NoOutput; - fn into_exec_output(self) -> NoOutput { - NoOutput + fn write_back(&mut self, value: String) { + **self = PhpMixed::String(value); } } -impl<'a> IntoExecOutput<'a> for Option<&'a mut PhpMixed> { - type Sink = PhpMixedOutput<'a>; - fn into_exec_output(self) -> PhpMixedOutput<'a> { - PhpMixedOutput(self) +/// `execute($cmd, $out)` where `$out` is consumed as a string: output is captured and assigned back +/// directly. +impl<'a> IntoExecOutput<'a> for &'a mut String { + fn capture_output(&self) -> bool { + true } -} -impl<'a> IntoExecOutput<'a> for &'a mut PhpMixed { - type Sink = PhpMixedOutput<'a>; - fn into_exec_output(self) -> PhpMixedOutput<'a> { - PhpMixedOutput(Some(self)) + fn to_callback(self) -> Result<Box<dyn FnMut(&str, &str) -> bool>, Self> { + Err(self) + } + + fn write_back(&mut self, value: String) { + **self = value; } } -impl<'a> IntoExecOutput<'a> for &'a mut String { - type Sink = StringOutput<'a>; - fn into_exec_output(self) -> StringOutput<'a> { - StringOutput(self) +/// `execute($cmd, $cb)` where `$cb` is callable: the callback is passed straight to `Process::run` +/// as the output handler, so the caller drives the child's output itself (e.g. `Svn`'s streaming +/// handler). The `bool` return mirrors Symfony's ignored callback return value. +impl<'a> IntoExecOutput<'a> for Box<dyn FnMut(&str, &str) -> bool> { + fn capture_output(&self) -> bool { + false } + + fn to_callback(self) -> Result<Box<dyn FnMut(&str, &str) -> bool>, Self> { + Ok(self) + } + + fn write_back(&mut self, _value: String) {} } /// Phase B helper: accept either `i64` or `PhpMixed` for `set_timeout`. diff --git a/crates/shirabe/src/util/svn.rs b/crates/shirabe/src/util/svn.rs index 84e5760..5375447 100644 --- a/crates/shirabe/src/util/svn.rs +++ b/crates/shirabe/src/util/svn.rs @@ -139,36 +139,32 @@ impl Svn { // Regenerate the command at each try, to use the newly user-provided credentials let command = self.get_command(svn_command.clone(), url, path); - let mut output: Option<String> = None; - // PHP: $handler = function ($type, $buffer) use (&$output, $io, $verbose) { ... }; - // $status = $this->process->execute($command, $handler, $cwd); - // TODO(phase-c): ProcessExecutor::execute does not yet accept a streaming output callback - // (its Symfony Process backing stays todo!()), so this handler — which filters by stream - // type, drops "Redirecting to URL" lines, accumulates into `output`, and echoes when - // verbose — cannot be passed through. The plain-buffer execute_args call below loses that - // filtering; resolving needs the process callback model (cf. process_executor.rs). - let _io = &self.io; - let _handler = |r#type: &str, buffer: &str| -> Option<()> { - if r#type != "out" { - return None; - } - if strpos(buffer, "Redirecting to URL ") == Some(0) { - return None; - } - // PHP: $output .= $buffer; - output.get_or_insert_with(String::new).push_str(buffer); - if verbose { - // self.io.write_error(PhpMixed::String(buffer.to_string()), false, io_interface::NORMAL); - } - None - }; - // TODO(phase-c): pass the filtering handler above to process.execute once the callback - // model lands; for now a plain buffer is used and the output filtering is skipped. - let mut handler_output = String::new(); + let output: std::rc::Rc<std::cell::RefCell<Option<String>>> = + std::rc::Rc::new(std::cell::RefCell::new(None)); + let io = self.io.clone(); + let output_for_handler = output.clone(); + let handler: Box<dyn FnMut(&str, &str) -> bool> = + Box::new(move |r#type: &str, buffer: &str| { + if r#type != "out" { + return false; + } + if strpos(buffer, "Redirecting to URL ") == Some(0) { + return false; + } + output_for_handler + .borrow_mut() + .get_or_insert_with(String::new) + .push_str(buffer); + if verbose { + io.borrow().write_error2(buffer, false); + } + false + }); let status = self .process .borrow_mut() - .execute_args(&command, &mut handler_output, cwd); + .execute(command.as_slice(), handler, cwd)?; + let output = output.borrow().clone(); if 0 == status { return Ok(output); } diff --git a/crates/shirabe/tests/platform/hhvm_detector_test.rs b/crates/shirabe/tests/platform/hhvm_detector_test.rs index 72fd68d..5bf96d2 100644 --- a/crates/shirabe/tests/platform/hhvm_detector_test.rs +++ b/crates/shirabe/tests/platform/hhvm_detector_test.rs @@ -57,9 +57,7 @@ fn test_hhvm_version_when_executing_in_php() { "{} --php -d hhvm.jit=0 -r \"echo HHVM_VERSION;\" 2>/dev/null", ProcessExecutor::escape(&hhvm) ); - let exit_code = process - .execute(cmd.as_str(), Some(&mut version), None) - .unwrap(); + let exit_code = process.execute(cmd.as_str(), &mut version, None).unwrap(); assert_eq!(0, exit_code); let version = version diff --git a/crates/shirabe/tests/util/process_executor_test.rs b/crates/shirabe/tests/util/process_executor_test.rs index 3ee4912..ba3177f 100644 --- a/crates/shirabe/tests/util/process_executor_test.rs +++ b/crates/shirabe/tests/util/process_executor_test.rs @@ -152,7 +152,7 @@ fn test_console_io_does_not_format_symfony_console_style() { process .execute( r#"php -ddisplay_errors=0 -derror_reporting=0 -r "echo '<error>foo</error>'.PHP_EOL;""#, - (), + ProcessExecutor::FORWARD_OUTPUT, None, ) .unwrap(); |
