-
-
Notifications
You must be signed in to change notification settings - Fork 140
✨ zb: Add support for unixexec transport
#976
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
b02f508
✏️ zb: Fix typo in transport module comment
vially 5b02921
♻️ zb: Enable process abstraction for all `unix` targets
vially 6b4ebc3
♻️ zb: Add thin wrapper over async `Command` types
vially f4e82da
🔌 zb: Add `Command` stdio socket type
vially cc05e6e
✨ zb: Add support for `unixexec` transport
vially 0fd431b
✅ zb: Add `unixexec` connection test case
vially File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,20 +1,103 @@ | ||
| use std::{ffi::OsStr, io::Error, process::Output}; | ||
| #[cfg(not(feature = "tokio"))] | ||
| use async_process::{unix::CommandExt, Child}; | ||
| #[cfg(target_os = "macos")] | ||
| use std::process::Output; | ||
| use std::{ffi::OsStr, io::Error, process::Stdio}; | ||
| #[cfg(feature = "tokio")] | ||
| use tokio::process::Child; | ||
|
|
||
| use crate::address::transport::Unixexec; | ||
|
|
||
| /// A wrapper around the command API of the underlying async runtime. | ||
| pub struct Command( | ||
| #[cfg(not(feature = "tokio"))] async_process::Command, | ||
| #[cfg(feature = "tokio")] tokio::process::Command, | ||
| ); | ||
|
|
||
| impl Command { | ||
| /// Constructs a new `Command` for launching the program at path `program`. | ||
| pub fn new<S>(program: S) -> Self | ||
| where | ||
| S: AsRef<OsStr>, | ||
| { | ||
| #[cfg(not(feature = "tokio"))] | ||
| return Self(async_process::Command::new(program)); | ||
|
|
||
| #[cfg(feature = "tokio")] | ||
| return Self(tokio::process::Command::new(program)); | ||
| } | ||
|
|
||
| /// Constructs a new `Command` from a `unixexec` address. | ||
| pub fn for_unixexec(unixexec: &Unixexec) -> Self { | ||
| let mut command = Self::new(unixexec.path()); | ||
| command.args(unixexec.args()); | ||
|
|
||
| if let Some(arg0) = unixexec.arg0() { | ||
| command.arg0(arg0); | ||
| } | ||
|
|
||
| command | ||
| } | ||
|
|
||
| /// Sets executable argument. | ||
| /// | ||
| /// Set the first process argument, `argv[0]`, to something other than the | ||
| /// default executable path. | ||
| pub fn arg0<S>(&mut self, arg: S) -> &mut Self | ||
| where | ||
| S: AsRef<OsStr>, | ||
| { | ||
| self.0.arg0(arg); | ||
| self | ||
| } | ||
|
|
||
| /// Adds multiple arguments to pass to the program. | ||
| pub fn args<I, S>(&mut self, args: I) -> &mut Self | ||
| where | ||
| I: IntoIterator<Item = S>, | ||
| S: AsRef<OsStr>, | ||
| { | ||
| self.0.args(args); | ||
| self | ||
| } | ||
|
|
||
| /// Executes the command as a child process, waiting for it to finish and | ||
| /// collecting all of its output. | ||
| #[cfg(target_os = "macos")] | ||
| pub async fn output(&mut self) -> Result<Output, Error> { | ||
| self.0.output().await | ||
| } | ||
|
|
||
| /// Sets configuration for the child process's standard input (stdin) handle. | ||
| pub fn stdin<T: Into<Stdio>>(&mut self, cfg: T) -> &mut Self { | ||
| self.0.stdin(cfg); | ||
| self | ||
| } | ||
|
|
||
| /// Sets configuration for the child process's standard output (stdout) handle. | ||
| pub fn stdout<T: Into<Stdio>>(&mut self, cfg: T) -> &mut Self { | ||
| self.0.stdout(cfg); | ||
| self | ||
| } | ||
|
|
||
| /// Sets configuration for the child process's standard error (stderr) handle. | ||
| pub fn stderr<T: Into<Stdio>>(&mut self, cfg: T) -> &mut Self { | ||
| self.0.stderr(cfg); | ||
| self | ||
| } | ||
|
|
||
| /// Executes the command as a child process, returning a handle to it. | ||
| pub fn spawn(&mut self) -> Result<Child, Error> { | ||
| self.0.spawn() | ||
| } | ||
| } | ||
|
|
||
| /// An asynchronous wrapper around running and getting command output | ||
| #[cfg(target_os = "macos")] | ||
| pub async fn run<I, S>(program: S, args: I) -> Result<Output, Error> | ||
| where | ||
| I: IntoIterator<Item = S>, | ||
| S: AsRef<OsStr>, | ||
| { | ||
| #[cfg(not(feature = "tokio"))] | ||
| return async_process::Command::new(program) | ||
| .args(args) | ||
| .output() | ||
| .await; | ||
|
|
||
| #[cfg(feature = "tokio")] | ||
| return tokio::process::Command::new(program) | ||
| .args(args) | ||
| .output() | ||
| .await; | ||
| Command::new(program).args(args).output().await | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,115 @@ | ||
| use std::{ | ||
| borrow::BorrowMut, ffi::OsString, fmt::Display, os::unix::ffi::OsStrExt, path::PathBuf, | ||
| process::Stdio, | ||
| }; | ||
|
|
||
| use crate::process::Command; | ||
|
|
||
| use super::encode_percents; | ||
|
|
||
| /// `unixexec:` D-Bus transport. | ||
| /// | ||
| /// <https://dbus.freedesktop.org/doc/dbus-specification.html#transports-exec> | ||
| #[derive(Clone, Debug, PartialEq, Eq)] | ||
| pub struct Unixexec { | ||
| path: PathBuf, | ||
| arg0: Option<OsString>, | ||
| args: Vec<OsString>, | ||
| } | ||
|
|
||
| impl Unixexec { | ||
| /// Create a new unixexec transport with the given path and arguments. | ||
| pub fn new(path: PathBuf, arg0: Option<OsString>, args: Vec<OsString>) -> Self { | ||
| Self { path, arg0, args } | ||
| } | ||
|
|
||
| pub(super) fn from_options(opts: std::collections::HashMap<&str, &str>) -> crate::Result<Self> { | ||
| let Some(path) = opts.get("path") else { | ||
| return Err(crate::Error::Address( | ||
| "unixexec address is missing `path`".to_owned(), | ||
| )); | ||
| }; | ||
|
|
||
| let arg0 = opts.get("argv0").map(OsString::from); | ||
|
|
||
| let mut args: Vec<OsString> = Vec::new(); | ||
| let mut arg_index = 1; | ||
| while let Some(arg) = opts.get(format!("argv{arg_index}").as_str()) { | ||
| args.push(OsString::from(arg)); | ||
| arg_index += 1; | ||
| } | ||
|
|
||
| Ok(Self::new(PathBuf::from(path), arg0, args)) | ||
| } | ||
|
|
||
| /// Binary to execute. | ||
| /// | ||
| /// Path of the binary to execute, either an absolute path or a binary name that is searched for | ||
| /// in the default search path of the OS. This corresponds to the first argument of execlp(). | ||
| /// This key is mandatory. | ||
| pub fn path(&self) -> &PathBuf { | ||
| &self.path | ||
| } | ||
|
|
||
| /// The executable argument. | ||
| /// | ||
| /// The program name to use when executing the binary. If omitted the same | ||
| /// value as specified for path will be used. This corresponds to the | ||
| /// second argument of execlp(). | ||
| pub fn arg0(&self) -> Option<&OsString> { | ||
| self.arg0.as_ref() | ||
| } | ||
|
|
||
| /// Arguments. | ||
| /// | ||
| /// Arguments to pass to the binary. | ||
| pub fn args(&self) -> &[OsString] { | ||
| self.args.as_ref() | ||
| } | ||
|
|
||
| pub(super) async fn connect(&self) -> crate::Result<crate::connection::socket::Command> { | ||
| Command::for_unixexec(self) | ||
| .stdin(Stdio::piped()) | ||
| .stdout(Stdio::piped()) | ||
| .stderr(Stdio::inherit()) | ||
| .spawn()? | ||
| .borrow_mut() | ||
| .try_into() | ||
| } | ||
| } | ||
|
|
||
| impl Display for Unixexec { | ||
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
| f.write_str("unixexec:path=")?; | ||
| encode_percents(f, self.path.as_os_str().as_bytes())?; | ||
|
|
||
| if let Some(arg0) = self.arg0.as_ref() { | ||
| f.write_str(",argv0=")?; | ||
| encode_percents(f, arg0.as_bytes())?; | ||
| } | ||
|
|
||
| for (index, arg) in self.args.iter().enumerate() { | ||
| write!(f, ",argv{}=", index + 1)?; | ||
| encode_percents(f, arg.as_bytes())?; | ||
| } | ||
|
|
||
| Ok(()) | ||
| } | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use crate::address::{transport::Transport, Address}; | ||
|
|
||
| #[test] | ||
| fn connect() { | ||
| let addr: Address = "unixexec:path=echo,argv1=hello,argv2=world" | ||
| .try_into() | ||
| .unwrap(); | ||
| let unixexec = match addr.transport() { | ||
| Transport::Unixexec(unixexec) => unixexec, | ||
| _ => unreachable!(), | ||
| }; | ||
| crate::utils::block_on(unixexec.connect()).unwrap(); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.