summaryrefslogtreecommitdiffstats
path: root/src/pipeline/builtins/command.rs
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2022-01-09 22:46:15 -0500
committerJesse Luehrs <doy@tozt.net>2022-01-09 22:46:15 -0500
commitcba75be9c673b846ad0c4f6f5f2e8461056582ad (patch)
treec755fdea87b947cc62984da060220acfa46e8a0d /src/pipeline/builtins/command.rs
parent973346c5e426d6a1b684d36ba779bf3e8f5b71b1 (diff)
downloadnbsh-cba75be9c673b846ad0c4f6f5f2e8461056582ad.tar.gz
nbsh-cba75be9c673b846ad0c4f6f5f2e8461056582ad.zip
rename
since this doesn't just run pipelines anymore
Diffstat (limited to 'src/pipeline/builtins/command.rs')
-rw-r--r--src/pipeline/builtins/command.rs398
1 files changed, 0 insertions, 398 deletions
diff --git a/src/pipeline/builtins/command.rs b/src/pipeline/builtins/command.rs
deleted file mode 100644
index 40498fc..0000000
--- a/src/pipeline/builtins/command.rs
+++ /dev/null
@@ -1,398 +0,0 @@
-use crate::pipeline::prelude::*;
-
-use async_std::io::prelude::BufReadExt as _;
-
-pub struct Command {
- exe: crate::parse::Exe,
- f: super::Builtin,
- cfg: Cfg,
-}
-
-impl Command {
- pub fn new(exe: crate::parse::Exe) -> Result<Self, crate::parse::Exe> {
- if let Some(s) = exe.exe().to_str() {
- if let Some(f) = super::BUILTINS.get(s) {
- Ok(Self {
- exe,
- f,
- cfg: Cfg::new(),
- })
- } else {
- Err(exe)
- }
- } else {
- Err(exe)
- }
- }
-
- pub fn new_with_io(
- exe: crate::parse::Exe,
- io: Io,
- ) -> Result<Self, crate::parse::Exe> {
- if let Some(s) = exe.exe().to_str() {
- if let Some(f) = super::BUILTINS.get(s) {
- Ok(Self {
- exe,
- f,
- cfg: Cfg::new_with_io(io),
- })
- } else {
- Err(exe)
- }
- } else {
- Err(exe)
- }
- }
-
- pub fn stdin(&mut self, fh: std::fs::File) {
- self.cfg.io.set_stdin(fh);
- }
-
- pub fn stdout(&mut self, fh: std::fs::File) {
- self.cfg.io.set_stdout(fh);
- }
-
- pub fn stderr(&mut self, fh: std::fs::File) {
- self.cfg.io.set_stderr(fh);
- }
-
- // Safety: see pre_exec in async_std::os::unix::process::CommandExt (this
- // is just a wrapper)
- pub unsafe fn pre_exec<F>(&mut self, f: F)
- where
- F: 'static + FnMut() -> std::io::Result<()> + Send + Sync,
- {
- self.cfg.pre_exec(f);
- }
-
- pub fn apply_redirects(&mut self, redirects: &[crate::parse::Redirect]) {
- self.cfg.io.apply_redirects(redirects);
- }
-
- pub fn spawn(self, env: &Env) -> anyhow::Result<Child> {
- let Self { f, exe, cfg } = self;
- (f)(exe, env, cfg)
- }
-}
-
-pub struct Cfg {
- io: Io,
- pre_exec: Option<
- Box<dyn 'static + FnMut() -> std::io::Result<()> + Send + Sync>,
- >,
-}
-
-impl Cfg {
- fn new() -> Self {
- Self {
- io: Io::new(),
- pre_exec: None,
- }
- }
-
- fn new_with_io(io: Io) -> Self {
- Self { io, pre_exec: None }
- }
-
- pub fn io(&self) -> &Io {
- &self.io
- }
-
- // Safety: see pre_exec in async_std::os::unix::process::CommandExt (this
- // is just a wrapper)
- pub unsafe fn pre_exec<F>(&mut self, f: F)
- where
- F: 'static + FnMut() -> std::io::Result<()> + Send + Sync,
- {
- self.pre_exec = Some(Box::new(f));
- }
-
- pub fn setup_command(mut self, cmd: &mut crate::pipeline::Command) {
- self.io.setup_command(cmd);
- if let Some(pre_exec) = self.pre_exec.take() {
- // Safety: pre_exec can only have been set by calling the pre_exec
- // method, which is itself unsafe, so the safety comments at the
- // point where that is called are the relevant ones
- unsafe { cmd.pre_exec(pre_exec) };
- }
- }
-}
-
-#[derive(Debug, Clone)]
-pub struct Io {
- fds: std::collections::HashMap<
- std::os::unix::io::RawFd,
- crate::mutex::Mutex<File>,
- >,
-}
-
-impl Io {
- pub fn new() -> Self {
- Self {
- fds: std::collections::HashMap::new(),
- }
- }
-
- fn stdin(&self) -> Option<crate::mutex::Mutex<File>> {
- self.fds.get(&0).map(crate::mutex::clone)
- }
-
- pub fn set_stdin<T: std::os::unix::io::IntoRawFd>(&mut self, stdin: T) {
- if let Some(file) = self.fds.remove(&0) {
- File::maybe_drop(file);
- }
- self.fds.insert(
- 0,
- // Safety: we just acquired stdin via into_raw_fd, which acquires
- // ownership of the fd, so we are now the sole owner
- crate::mutex::new(unsafe { File::input(stdin.into_raw_fd()) }),
- );
- }
-
- fn stdout(&self) -> Option<crate::mutex::Mutex<File>> {
- self.fds.get(&1).map(crate::mutex::clone)
- }
-
- pub fn set_stdout<T: std::os::unix::io::IntoRawFd>(&mut self, stdout: T) {
- if let Some(file) = self.fds.remove(&1) {
- File::maybe_drop(file);
- }
- self.fds.insert(
- 1,
- // Safety: we just acquired stdout via into_raw_fd, which acquires
- // ownership of the fd, so we are now the sole owner
- crate::mutex::new(unsafe { File::output(stdout.into_raw_fd()) }),
- );
- }
-
- fn stderr(&self) -> Option<crate::mutex::Mutex<File>> {
- self.fds.get(&2).map(crate::mutex::clone)
- }
-
- pub fn set_stderr<T: std::os::unix::io::IntoRawFd>(&mut self, stderr: T) {
- if let Some(file) = self.fds.remove(&2) {
- File::maybe_drop(file);
- }
- self.fds.insert(
- 2,
- // Safety: we just acquired stderr via into_raw_fd, which acquires
- // ownership of the fd, so we are now the sole owner
- crate::mutex::new(unsafe { File::output(stderr.into_raw_fd()) }),
- );
- }
-
- pub fn apply_redirects(&mut self, redirects: &[crate::parse::Redirect]) {
- for redirect in redirects {
- let to = match &redirect.to {
- crate::parse::RedirectTarget::Fd(fd) => {
- crate::mutex::clone(&self.fds[fd])
- }
- crate::parse::RedirectTarget::File(path) => {
- let fd = redirect.dir.open(path).unwrap();
- match redirect.dir {
- crate::parse::Direction::In => {
- // Safety: we just opened fd, and nothing else has
- // or can use it
- crate::mutex::new(unsafe { File::input(fd) })
- }
- crate::parse::Direction::Out
- | crate::parse::Direction::Append => {
- // Safety: we just opened fd, and nothing else has
- // or can use it
- crate::mutex::new(unsafe { File::output(fd) })
- }
- }
- }
- };
- self.fds.insert(redirect.from, to);
- }
- }
-
- pub async fn read_line_stdin(&self) -> anyhow::Result<String> {
- let mut buf = String::new();
- if let Some(fh) = self.stdin() {
- if let File::In(fh) = &mut *fh.lock_arc().await {
- fh.read_line(&mut buf).await?;
- }
- }
- if buf.ends_with('\n') {
- buf.truncate(buf.len() - 1);
- }
- Ok(buf)
- }
-
- pub async fn write_stdout(&self, buf: &[u8]) -> anyhow::Result<()> {
- if let Some(fh) = self.stdout() {
- if let File::Out(fh) = &mut *fh.lock_arc().await {
- Ok(fh.write_all(buf).await.map(|_| ())?)
- } else {
- Ok(())
- }
- } else {
- Ok(())
- }
- }
-
- pub async fn write_stderr(&self, buf: &[u8]) -> anyhow::Result<()> {
- if let Some(fh) = self.stderr() {
- if let File::Out(fh) = &mut *fh.lock_arc().await {
- Ok(fh.write_all(buf).await.map(|_| ())?)
- } else {
- Ok(())
- }
- } else {
- Ok(())
- }
- }
-
- pub fn setup_command(mut self, cmd: &mut crate::pipeline::Command) {
- if let Some(stdin) = self.fds.remove(&0) {
- if let Some(stdin) = crate::mutex::unwrap(stdin) {
- let stdin = stdin.into_raw_fd();
- if stdin != 0 {
- // Safety: we just acquired stdin via into_raw_fd, which
- // acquires ownership of the fd, so we are now the sole
- // owner
- cmd.stdin(unsafe { std::fs::File::from_raw_fd(stdin) });
- self.fds.remove(&0);
- }
- }
- }
- if let Some(stdout) = self.fds.remove(&1) {
- if let Some(stdout) = crate::mutex::unwrap(stdout) {
- let stdout = stdout.into_raw_fd();
- if stdout != 1 {
- // Safety: we just acquired stdout via into_raw_fd, which
- // acquires ownership of the fd, so we are now the sole
- // owner
- cmd.stdout(unsafe { std::fs::File::from_raw_fd(stdout) });
- self.fds.remove(&1);
- }
- }
- }
- if let Some(stderr) = self.fds.remove(&2) {
- if let Some(stderr) = crate::mutex::unwrap(stderr) {
- let stderr = stderr.into_raw_fd();
- if stderr != 2 {
- // Safety: we just acquired stderr via into_raw_fd, which
- // acquires ownership of the fd, so we are now the sole
- // owner
- cmd.stderr(unsafe { std::fs::File::from_raw_fd(stderr) });
- self.fds.remove(&2);
- }
- }
- }
- }
-}
-
-impl Drop for Io {
- fn drop(&mut self) {
- for (_, file) in self.fds.drain() {
- File::maybe_drop(file);
- }
- }
-}
-
-#[derive(Debug)]
-pub enum File {
- In(async_std::io::BufReader<async_std::fs::File>),
- Out(async_std::fs::File),
-}
-
-impl File {
- // Safety: fd must not be owned by any other File object
- pub unsafe fn input(fd: std::os::unix::io::RawFd) -> Self {
- Self::In(async_std::io::BufReader::new(
- async_std::fs::File::from_raw_fd(fd),
- ))
- }
-
- // Safety: fd must not be owned by any other File object
- pub unsafe fn output(fd: std::os::unix::io::RawFd) -> Self {
- Self::Out(async_std::fs::File::from_raw_fd(fd))
- }
-
- fn maybe_drop(file: crate::mutex::Mutex<Self>) {
- if let Some(file) = crate::mutex::unwrap(file) {
- if file.as_raw_fd() <= 2 {
- let _ = file.into_raw_fd();
- }
- }
- }
-}
-
-impl std::os::unix::io::AsRawFd for File {
- fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
- match self {
- Self::In(fh) => fh.get_ref().as_raw_fd(),
- Self::Out(fh) => fh.as_raw_fd(),
- }
- }
-}
-
-impl std::os::unix::io::IntoRawFd for File {
- fn into_raw_fd(self) -> std::os::unix::io::RawFd {
- match self {
- Self::In(fh) => fh.into_inner().into_raw_fd(),
- Self::Out(fh) => fh.into_raw_fd(),
- }
- }
-}
-
-pub struct Child<'a> {
- fut: std::pin::Pin<
- Box<
- dyn std::future::Future<Output = std::process::ExitStatus>
- + Sync
- + Send
- + 'a,
- >,
- >,
- wrapped_child: Option<Box<crate::pipeline::Child<'a>>>,
-}
-
-impl<'a> Child<'a> {
- pub fn new_fut<F>(fut: F) -> Self
- where
- F: std::future::Future<Output = std::process::ExitStatus>
- + Sync
- + Send
- + 'a,
- {
- Self {
- fut: Box::pin(fut),
- wrapped_child: None,
- }
- }
-
- pub fn new_wrapped(child: crate::pipeline::Child<'a>) -> Self {
- Self {
- fut: Box::pin(async move { unreachable!() }),
- wrapped_child: Some(Box::new(child)),
- }
- }
-
- pub fn id(&self) -> Option<u32> {
- self.wrapped_child.as_ref().and_then(|cmd| cmd.id())
- }
-
- pub fn status(
- self,
- ) -> std::pin::Pin<
- Box<
- dyn std::future::Future<
- Output = anyhow::Result<async_std::process::ExitStatus>,
- > + Send
- + Sync
- + 'a,
- >,
- > {
- Box::pin(async move {
- if let Some(child) = self.wrapped_child {
- child.status().await
- } else {
- Ok(self.fut.await)
- }
- })
- }
-}