mirror of
https://github.com/nushell/nushell
synced 2024-12-27 21:43:09 +00: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
4 changed files with 55 additions and 1 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -3259,6 +3259,7 @@ dependencies = [
|
||||||
"nu-test-support",
|
"nu-test-support",
|
||||||
"nu-utils",
|
"nu-utils",
|
||||||
"num-format",
|
"num-format",
|
||||||
|
"os_pipe",
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
"rmp-serde",
|
"rmp-serde",
|
||||||
"rstest",
|
"rstest",
|
||||||
|
|
|
@ -119,7 +119,7 @@ num-traits = "0.2"
|
||||||
omnipath = "0.1"
|
omnipath = "0.1"
|
||||||
once_cell = "1.18"
|
once_cell = "1.18"
|
||||||
open = "5.1"
|
open = "5.1"
|
||||||
os_pipe = "1.1"
|
os_pipe = { version = "1.1", features = ["io_safety"] }
|
||||||
pathdiff = "0.2"
|
pathdiff = "0.2"
|
||||||
percent-encoding = "2"
|
percent-encoding = "2"
|
||||||
pretty_assertions = "1.4"
|
pretty_assertions = "1.4"
|
||||||
|
|
|
@ -47,6 +47,7 @@ nu-test-support = { path = "../nu-test-support", version = "0.93.1" }
|
||||||
pretty_assertions = { workspace = true }
|
pretty_assertions = { workspace = true }
|
||||||
rstest = { workspace = true }
|
rstest = { workspace = true }
|
||||||
tempfile = { workspace = true }
|
tempfile = { workspace = true }
|
||||||
|
os_pipe = { workspace = true }
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
all-features = true
|
all-features = true
|
||||||
|
|
|
@ -7,6 +7,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
|
fs::File,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -593,6 +594,57 @@ impl Stack {
|
||||||
self
|
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`.
|
/// Set the PWD environment variable to `path`.
|
||||||
///
|
///
|
||||||
/// This method accepts `path` with trailing slashes, but they're removed
|
/// This method accepts `path` with trailing slashes, but they're removed
|
||||||
|
|
Loading…
Reference in a new issue