aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2021-12-30 23:14:55 -0500
committerJesse Luehrs <doy@tozt.net>2021-12-30 23:14:55 -0500
commit09ff545fe44242734d5f6daf4a74946d2f04728d (patch)
tree79e5b7080dd58137020748fcaf15fb089493b864
parenta5b7f59b19052b69f3ada89e4b07c1fb6dbfaf34 (diff)
downloadpty-process-09ff545fe44242734d5f6daf4a74946d2f04728d.tar.gz
pty-process-09ff545fe44242734d5f6daf4a74946d2f04728d.zip
docs
-rw-r--r--src/blocking/command.rs32
-rw-r--r--src/blocking/mod.rs3
-rw-r--r--src/blocking/pty.rs9
-rw-r--r--src/command.rs33
-rw-r--r--src/error.rs2
-rw-r--r--src/lib.rs32
-rw-r--r--src/pty.rs10
7 files changed, 120 insertions, 1 deletions
diff --git a/src/blocking/command.rs b/src/blocking/command.rs
index 0fa97ea..6c4a825 100644
--- a/src/blocking/command.rs
+++ b/src/blocking/command.rs
@@ -1,5 +1,6 @@
use std::os::unix::process::CommandExt as _;
+/// Wrapper around [`std::process::Command`]
pub struct Command {
inner: std::process::Command,
stdin: bool,
@@ -12,6 +13,7 @@ pub struct Command {
}
impl Command {
+ /// See [`std::process::Command::new`]
pub fn new<S: AsRef<std::ffi::OsStr>>(program: S) -> Self {
Self {
inner: std::process::Command::new(program),
@@ -23,11 +25,13 @@ impl Command {
}
}
+ /// See [`std::process::Command::arg`]
pub fn arg<S: AsRef<std::ffi::OsStr>>(&mut self, arg: S) -> &mut Self {
self.inner.arg(arg);
self
}
+ /// See [`std::process::Command::args`]
pub fn args<I, S>(&mut self, args: I) -> &mut Self
where
I: IntoIterator<Item = S>,
@@ -37,6 +41,7 @@ impl Command {
self
}
+ /// See [`std::process::Command::env`]
pub fn env<K, V>(&mut self, key: K, val: V) -> &mut Self
where
K: AsRef<std::ffi::OsStr>,
@@ -46,6 +51,7 @@ impl Command {
self
}
+ /// See [`std::process::Command::envs`]
pub fn envs<I, K, V>(&mut self, vars: I) -> &mut Self
where
I: IntoIterator<Item = (K, V)>,
@@ -56,6 +62,7 @@ impl Command {
self
}
+ /// See [`std::process::Command::env_remove`]
pub fn env_remove<K: AsRef<std::ffi::OsStr>>(
&mut self,
key: K,
@@ -64,11 +71,13 @@ impl Command {
self
}
+ /// See [`std::process::Command::env_clear`]
pub fn env_clear(&mut self) -> &mut Self {
self.inner.env_clear();
self
}
+ /// See [`std::process::Command::current_dir`]
pub fn current_dir<P: AsRef<std::path::Path>>(
&mut self,
dir: P,
@@ -77,6 +86,7 @@ impl Command {
self
}
+ /// See [`std::process::Command::stdin`]
pub fn stdin<T: Into<std::process::Stdio>>(
&mut self,
cfg: T,
@@ -86,6 +96,7 @@ impl Command {
self
}
+ /// See [`std::process::Command::stdout`]
pub fn stdout<T: Into<std::process::Stdio>>(
&mut self,
cfg: T,
@@ -95,6 +106,7 @@ impl Command {
self
}
+ /// See [`std::process::Command::stderr`]
pub fn stderr<T: Into<std::process::Stdio>>(
&mut self,
cfg: T,
@@ -104,6 +116,22 @@ impl Command {
self
}
+ /// Executes the command as a child process via
+ /// [`std::process::Command::spawn`], and attaches the given `pty` to
+ /// that child. The pty will be attached to all of `stdin`, `stdout`, and
+ /// `stderr` of the child, unless those file descriptors were previously
+ /// overridden through calls to [`stdin`](Self::stdin),
+ /// [`stdout`](Self::stdout), or [`stderr`](Self::stderr). The newly
+ /// created child process will also be made the session leader of a new
+ /// session, and will have the given `pty` instance set as its controlling
+ /// terminal.
+ ///
+ /// # Errors
+ /// Returns an error if we fail to allocate new file descriptors for
+ /// attaching the pty to the child process, or if we fail to spawn the
+ /// child process (see the documentation for
+ /// [`std::process::Command::spawn`]), or if we fail to make the child a
+ /// session leader or set its controlling terminal.
pub fn spawn(
&mut self,
pty: &crate::blocking::Pty,
@@ -140,16 +168,20 @@ impl Command {
Ok(self.inner.spawn()?)
}
+ /// See [`std::os::unix::process::CommandExt::uid`]
pub fn uid(&mut self, id: u32) -> &mut Self {
self.inner.uid(id);
self
}
+ /// See [`std::os::unix::process::CommandExt::gid`]
pub fn gid(&mut self, id: u32) -> &mut Self {
self.inner.gid(id);
self
}
+ /// See [`std::os::unix::process::CommandExt::pre_exec`]
+ #[allow(clippy::missing_safety_doc)]
pub unsafe fn pre_exec<F>(&mut self, f: F) -> &mut Self
where
F: FnMut() -> std::io::Result<()> + Send + Sync + 'static,
diff --git a/src/blocking/mod.rs b/src/blocking/mod.rs
index cdf66da..17a0733 100644
--- a/src/blocking/mod.rs
+++ b/src/blocking/mod.rs
@@ -1,3 +1,6 @@
+//! Blocking equivalents for [`pty_process::Command`](crate::Command) and
+//! [`pty_process::Pty`](crate::Pty)
+
mod command;
pub use command::Command;
mod pty;
diff --git a/src/blocking/pty.rs b/src/blocking/pty.rs
index d864bd6..6fa3382 100644
--- a/src/blocking/pty.rs
+++ b/src/blocking/pty.rs
@@ -1,9 +1,14 @@
+/// An allocated pty
pub struct Pty {
pt: std::fs::File,
pts: std::fs::File,
}
impl Pty {
+ /// Allocate and return a new pty.
+ ///
+ /// # Errors
+ /// Returns an error if the pty failed to be allocated.
pub fn new() -> crate::Result<Self> {
let (pt, ptsname) = crate::sys::create_pt()?;
let pts = std::fs::OpenOptions::new()
@@ -13,6 +18,10 @@ impl Pty {
Ok(Self { pt, pts })
}
+ /// Change the terminal size associated with the pty.
+ ///
+ /// # Errors
+ /// Returns an error if we were unable to set the terminal size.
pub fn resize(&self, size: crate::Size) -> crate::Result<()> {
Ok(crate::sys::set_term_size(self, size)?)
}
diff --git a/src/command.rs b/src/command.rs
index 00b51e7..8627a35 100644
--- a/src/command.rs
+++ b/src/command.rs
@@ -1,5 +1,6 @@
use async_process::unix::CommandExt as _;
+/// Wrapper around [`async_process::Command`]
pub struct Command {
inner: async_process::Command,
stdin: bool,
@@ -12,6 +13,7 @@ pub struct Command {
}
impl Command {
+ /// See [`async_process::Command::new`]
pub fn new<S: AsRef<std::ffi::OsStr>>(program: S) -> Self {
Self {
inner: async_process::Command::new(program),
@@ -23,11 +25,13 @@ impl Command {
}
}
+ /// See [`async_process::Command::arg`]
pub fn arg<S: AsRef<std::ffi::OsStr>>(&mut self, arg: S) -> &mut Self {
self.inner.arg(arg);
self
}
+ /// See [`async_process::Command::args`]
pub fn args<I, S>(&mut self, args: I) -> &mut Self
where
I: IntoIterator<Item = S>,
@@ -37,6 +41,7 @@ impl Command {
self
}
+ /// See [`async_process::Command::env`]
pub fn env<K, V>(&mut self, key: K, val: V) -> &mut Self
where
K: AsRef<std::ffi::OsStr>,
@@ -46,6 +51,7 @@ impl Command {
self
}
+ /// See [`async_process::Command::envs`]
pub fn envs<I, K, V>(&mut self, vars: I) -> &mut Self
where
I: IntoIterator<Item = (K, V)>,
@@ -56,6 +62,7 @@ impl Command {
self
}
+ /// See [`async_process::Command::env_remove`]
pub fn env_remove<K: AsRef<std::ffi::OsStr>>(
&mut self,
key: K,
@@ -64,11 +71,13 @@ impl Command {
self
}
+ /// See [`async_process::Command::env_clear`]
pub fn env_clear(&mut self) -> &mut Self {
self.inner.env_clear();
self
}
+ /// See [`async_process::Command::current_dir`]
pub fn current_dir<P: AsRef<std::path::Path>>(
&mut self,
dir: P,
@@ -77,6 +86,7 @@ impl Command {
self
}
+ /// See [`async_process::Command::stdin`]
pub fn stdin<T: Into<std::process::Stdio>>(
&mut self,
cfg: T,
@@ -86,6 +96,7 @@ impl Command {
self
}
+ /// See [`async_process::Command::stdout`]
pub fn stdout<T: Into<std::process::Stdio>>(
&mut self,
cfg: T,
@@ -95,6 +106,7 @@ impl Command {
self
}
+ /// See [`async_process::Command::stderr`]
pub fn stderr<T: Into<std::process::Stdio>>(
&mut self,
cfg: T,
@@ -104,6 +116,22 @@ impl Command {
self
}
+ /// Executes the command as a child process via
+ /// [`async_process::Command::spawn`], and attaches the given `pty` to
+ /// that child. The pty will be attached to all of `stdin`, `stdout`, and
+ /// `stderr` of the child, unless those file descriptors were previously
+ /// overridden through calls to [`stdin`](Self::stdin),
+ /// [`stdout`](Self::stdout), or [`stderr`](Self::stderr). The newly
+ /// created child process will also be made the session leader of a new
+ /// session, and will have the given `pty` instance set as its controlling
+ /// terminal.
+ ///
+ /// # Errors
+ /// Returns an error if we fail to allocate new file descriptors for
+ /// attaching the pty to the child process, or if we fail to spawn the
+ /// child process (see the documentation for
+ /// [`async_process::Command::spawn`]), or if we fail to make the child a
+ /// session leader or set its controlling terminal.
pub fn spawn(
&mut self,
pty: &crate::Pty,
@@ -140,16 +168,20 @@ impl Command {
Ok(self.inner.spawn()?)
}
+ /// See [`async_process::unix::CommandExt::uid`]
pub fn uid(&mut self, id: u32) -> &mut Self {
self.inner.uid(id);
self
}
+ /// See [`async_process::unix::CommandExt::gid`]
pub fn gid(&mut self, id: u32) -> &mut Self {
self.inner.gid(id);
self
}
+ /// See [`async_process::unix::CommandExt::pre_exec`]
+ #[allow(clippy::missing_safety_doc)]
pub unsafe fn pre_exec<F>(&mut self, f: F) -> &mut Self
where
F: FnMut() -> std::io::Result<()> + Send + Sync + 'static,
@@ -158,6 +190,7 @@ impl Command {
self
}
+ /// See [`async_process::unix::CommandExt::arg0`]
pub fn arg0<S>(&mut self, arg: S) -> &mut Self
where
S: AsRef<std::ffi::OsStr>,
diff --git a/src/error.rs b/src/error.rs
index 57994df..9d4c31e 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -1,4 +1,4 @@
-/// Source for errors in this crate
+/// Error type for errors from this crate
#[derive(Debug)]
pub enum Error {
/// error came from std::io::Error
diff --git a/src/lib.rs b/src/lib.rs
index efb12de..a4bb412 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,3 +1,35 @@
+//! This crate is a wrapper around [`std::process::Command`] or
+//! [`async_process::Command`] which provides the ability to allocate a pty
+//! and spawn new processes attached to that pty, with the pty as their
+//! controlling terminal. This allows for manipulation of interactive
+//! programs.
+//!
+//! The basic functionality looks like this:
+//!
+//! ```no_run
+//! let mut pty = pty_process::Pty::new().unwrap();
+//! pty.resize(pty_process::Size::new(24, 80)).unwrap();
+//! let mut cmd = pty_process::Command::new("nethack");
+//! let child = cmd.spawn(&pty).unwrap();
+//! ```
+//!
+//! The returned `child` is a normal instance of [`async_process::Child`] (or
+//! [`std::process::Child`] for the [`blocking`](crate::blocking) variant),
+//! with its `stdin`/`stdout`/`stderr` file descriptors pointing at the given
+//! pty. The `pty` instance implements [`std::io::Read`] and
+//! [`std::io::Write`] (or [`futures_io::AsyncRead`] and
+//! [`futures_io::AsyncWrite`] for the [`blocking`] variant), and can be used
+//! to communicate with the child process. The child process will also be made
+//! a session leader of a new session, and the controlling terminal of that
+//! session will be set to the given pty.
+//!
+//! # Features
+//!
+//! By default, only the [`blocking`](crate::blocking) APIs are available. To
+//! include the asynchronous APIs, you must enable the `async` feature. See
+//! the `examples` directory in the repository for examples of how to use this
+//! crate with the various different asynchronous frameworks.
+
#![warn(clippy::cargo)]
#![warn(clippy::pedantic)]
#![warn(clippy::nursery)]
diff --git a/src/pty.rs b/src/pty.rs
index 5d398d4..1d7f113 100644
--- a/src/pty.rs
+++ b/src/pty.rs
@@ -1,9 +1,15 @@
+/// An allocated pty
pub struct Pty {
pt: async_io::Async<std::fs::File>,
pts: std::fs::File,
}
impl Pty {
+ /// Allocate and return a new pty.
+ ///
+ /// # Errors
+ /// Returns an error if the pty failed to be allocated, or if we were
+ /// unable to put it into non-blocking mode.
pub fn new() -> crate::Result<Self> {
let (pt, ptsname) = crate::sys::create_pt()?;
let pt = async_io::Async::new(pt)?;
@@ -14,6 +20,10 @@ impl Pty {
Ok(Self { pt, pts })
}
+ /// Change the terminal size associated with the pty.
+ ///
+ /// # Errors
+ /// Returns an error if we were unable to set the terminal size.
pub fn resize(&self, size: crate::Size) -> crate::Result<()> {
Ok(crate::sys::set_term_size(self, size)?)
}