mirror of
https://github.com/nushell/nushell.git
synced 2024-11-22 00:13:21 +01:00
Add Stack::stdout_file and Stack::stderr_file to capture stdout/-err of external commands (#12857)
# Description In this PR I added two new methods to `Stack`, `stdout_file` and `stderr_file`. These two modify the inner `StackOutDest` and set a `File` into the `stdout` and `stderr` respectively. Different to the `push_redirection` methods, these do not require to hold a guard up all the time but require ownership of the stack. This is primarly useful for applications that use `nu` as a language but not the `nushell`. This PR replaces my first attempt #12851 to add a way to capture stdout/-err of external commands. Capturing the stdout without having to write into a file is possible with crates like [`os_pipe`](https://docs.rs/os_pipe), an example for this is given in the doc comment of the `stdout_file` command and can be executed as a doctest (although it doesn't validate that you actually got any data). This implementation takes `File` as input to make it easier to implement on different operating systems without having to worry about `OwnedHandle` or `OwnedFd`. Also this doesn't expose any use `os_pipe` to not leak its types into this API, making it depend on it. As in my previous attempt, @IanManske guided me here. # User-Facing Changes This change has no effect on `nushell` and therefore no user-facing changes. # Tests + Formatting This only exposes a new way of using already existing code and has therefore no further testing. The doctest succeeds on my machine at least (x86 Windows, 64 Bit). # After Submitting All the required documentation is already part of this PR.
This commit is contained in:
parent
905ec88091
commit
aaf973bbba
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -3259,6 +3259,7 @@ dependencies = [
|
||||
"nu-test-support",
|
||||
"nu-utils",
|
||||
"num-format",
|
||||
"os_pipe",
|
||||
"pretty_assertions",
|
||||
"rmp-serde",
|
||||
"rstest",
|
||||
|
@ -119,7 +119,7 @@ num-traits = "0.2"
|
||||
omnipath = "0.1"
|
||||
once_cell = "1.18"
|
||||
open = "5.1"
|
||||
os_pipe = "1.1"
|
||||
os_pipe = { version = "1.1", features = ["io_safety"] }
|
||||
pathdiff = "0.2"
|
||||
percent-encoding = "2"
|
||||
pretty_assertions = "1.4"
|
||||
|
@ -47,6 +47,7 @@ nu-test-support = { path = "../nu-test-support", version = "0.93.1" }
|
||||
pretty_assertions = { workspace = true }
|
||||
rstest = { workspace = true }
|
||||
tempfile = { workspace = true }
|
||||
os_pipe = { workspace = true }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
@ -7,6 +7,7 @@ use crate::{
|
||||
};
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
fs::File,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
@ -593,6 +594,57 @@ impl Stack {
|
||||
self
|
||||
}
|
||||
|
||||
/// Replaces the default stdout of the stack with a given file.
|
||||
///
|
||||
/// This method configures the default stdout to redirect to a specified file.
|
||||
/// It is primarily useful for applications using `nu` as a language, where the stdout of
|
||||
/// external commands that are not explicitly piped can be redirected to a file.
|
||||
///
|
||||
/// # Using Pipes
|
||||
///
|
||||
/// For use in third-party applications pipes might be very useful as they allow using the
|
||||
/// stdout of external commands for different uses.
|
||||
/// For example the [`os_pipe`](https://docs.rs/os_pipe) crate provides a elegant way to to
|
||||
/// access the stdout.
|
||||
///
|
||||
/// ```
|
||||
/// # use std::{fs::File, io::{self, Read}, thread, error};
|
||||
/// # use nu_protocol::engine::Stack;
|
||||
/// #
|
||||
/// let (mut reader, writer) = os_pipe::pipe().unwrap();
|
||||
/// // Use a thread to avoid blocking the execution of the called command.
|
||||
/// let reader = thread::spawn(move || {
|
||||
/// let mut buf: Vec<u8> = Vec::new();
|
||||
/// reader.read_to_end(&mut buf)?;
|
||||
/// Ok::<_, io::Error>(buf)
|
||||
/// });
|
||||
///
|
||||
/// #[cfg(windows)]
|
||||
/// let file = std::os::windows::io::OwnedHandle::from(writer).into();
|
||||
/// #[cfg(unix)]
|
||||
/// let file = std::os::unix::io::OwnedFd::from(writer).into();
|
||||
///
|
||||
/// let stack = Stack::new().stdout_file(file);
|
||||
///
|
||||
/// // Execute some nu code.
|
||||
///
|
||||
/// drop(stack); // drop the stack so that the writer will be dropped too
|
||||
/// let buf = reader.join().unwrap().unwrap();
|
||||
/// // Do with your buffer whatever you want.
|
||||
/// ```
|
||||
pub fn stdout_file(mut self, file: File) -> Self {
|
||||
self.out_dest.stdout = OutDest::File(Arc::new(file));
|
||||
self
|
||||
}
|
||||
|
||||
/// Replaces the default stderr of the stack with a given file.
|
||||
///
|
||||
/// For more info, see [`stdout_file`](Self::stdout_file).
|
||||
pub fn stderr_file(mut self, file: File) -> Self {
|
||||
self.out_dest.stderr = OutDest::File(Arc::new(file));
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the PWD environment variable to `path`.
|
||||
///
|
||||
/// This method accepts `path` with trailing slashes, but they're removed
|
||||
|
Loading…
Reference in New Issue
Block a user