ChgClient is no longer an extension trait because:
a. Client object is not consumed and recreated in future-0.3 world, which
unblocks writing a simple wrapper struct.
b. async fn isn't allowed in trait.
Overall, the API should become simpler.
| Alphare |
| hg-reviewers |
ChgClient is no longer an extension trait because:
a. Client object is not consumed and recreated in future-0.3 world, which
unblocks writing a simple wrapper struct.
b. async fn isn't allowed in trait.
Overall, the API should become simpler.
| No Linters Available |
| No Unit Test Coverage |
| Path | Packages | |||
|---|---|---|---|---|
| M | rust/chg/src/clientext.rs (167 lines) | |||
| M | rust/chg/src/lib.rs (4 lines) |
| Commit | Parents | Author | Summary | Date |
|---|---|---|---|---|
| 53db28efa581 | 226e17d11fe0 | Yuya Nishihara | Apr 10 2020, 10:26 AM |
| // Copyright 2018 Yuya Nishihara <yuya@tcha.org> | // Copyright 2018 Yuya Nishihara <yuya@tcha.org> | ||||
| // | // | ||||
| // This software may be used and distributed according to the terms of the | // This software may be used and distributed according to the terms of the | ||||
| // GNU General Public License version 2 or any later version. | // GNU General Public License version 2 or any later version. | ||||
| //! cHg extensions to command server client. | //! cHg extensions to command server client. | ||||
| use bytes::{BufMut, Bytes, BytesMut}; | use bytes::{BufMut, BytesMut}; | ||||
| use std::ffi::OsStr; | use std::ffi::OsStr; | ||||
| use std::io; | use std::io; | ||||
| use std::mem; | use std::mem; | ||||
| use std::os::unix::ffi::OsStrExt; | use std::os::unix::ffi::OsStrExt; | ||||
| use std::os::unix::io::AsRawFd; | use std::os::unix::io::AsRawFd; | ||||
| use std::path::Path; | use std::path::Path; | ||||
| use tokio_hglib::protocol::{OneShotQuery, OneShotRequest}; | use tokio_hglib::UnixClient; | ||||
| use tokio_hglib::{Client, Connection}; | |||||
| use crate::attachio::AttachIo; | use crate::attachio; | ||||
| use crate::message::{self, Instruction}; | use crate::message::{self, Instruction, ServerSpec}; | ||||
| use crate::runcommand::ChgRunCommand; | use crate::runcommand; | ||||
| use crate::uihandler::SystemHandler; | use crate::uihandler::SystemHandler; | ||||
| pub trait ChgClientExt<C> | /// Command-server client that also supports cHg extensions. | ||||
| where | pub struct ChgClient { | ||||
| C: Connection + AsRawFd, | client: UnixClient, | ||||
| { | } | ||||
| impl ChgClient { | |||||
| /// Connects to a command server listening at the specified socket path. | |||||
| pub async fn connect(path: impl AsRef<Path>) -> io::Result<Self> { | |||||
| let client = UnixClient::connect(path).await?; | |||||
| Ok(ChgClient { client }) | |||||
| } | |||||
| /// Server capabilities, encoding, etc. | |||||
| pub fn server_spec(&self) -> &ServerSpec { | |||||
| self.client.server_spec() | |||||
| } | |||||
| /// Attaches the client file descriptors to the server. | /// Attaches the client file descriptors to the server. | ||||
| fn attach_io<I, O, E>(self, stdin: I, stdout: O, stderr: E) -> AttachIo<C, I, O, E> | pub async fn attach_io( | ||||
| where | &mut self, | ||||
| I: AsRawFd, | stdin: &impl AsRawFd, | ||||
| O: AsRawFd, | stdout: &impl AsRawFd, | ||||
| E: AsRawFd; | stderr: &impl AsRawFd, | ||||
| ) -> io::Result<()> { | |||||
| attachio::attach_io(self.client.borrow_protocol_mut(), stdin, stdout, stderr).await | |||||
| } | |||||
| /// Changes the working directory of the server. | /// Changes the working directory of the server. | ||||
| fn set_current_dir(self, dir: impl AsRef<Path>) -> OneShotRequest<C>; | pub async fn set_current_dir(&mut self, dir: impl AsRef<Path>) -> io::Result<()> { | ||||
| let dir_bytes = dir.as_ref().as_os_str().as_bytes().to_owned(); | |||||
| self.client | |||||
| .borrow_protocol_mut() | |||||
| .send_command_with_args("chdir", dir_bytes) | |||||
| .await | |||||
| } | |||||
| /// Updates the environment variables of the server. | /// Updates the environment variables of the server. | ||||
| fn set_env_vars_os( | pub async fn set_env_vars_os( | ||||
| self, | &mut self, | ||||
| vars: impl IntoIterator<Item = (impl AsRef<OsStr>, impl AsRef<OsStr>)>, | vars: impl IntoIterator<Item = (impl AsRef<OsStr>, impl AsRef<OsStr>)>, | ||||
| ) -> OneShotRequest<C>; | ) -> io::Result<()> { | ||||
| self.client | |||||
| .borrow_protocol_mut() | |||||
| .send_command_with_args("setenv", message::pack_env_vars_os(vars)) | |||||
| .await | |||||
| } | |||||
| /// Changes the process title of the server. | /// Changes the process title of the server. | ||||
| fn set_process_name(self, name: impl AsRef<OsStr>) -> OneShotRequest<C>; | pub async fn set_process_name(&mut self, name: impl AsRef<OsStr>) -> io::Result<()> { | ||||
| let name_bytes = name.as_ref().as_bytes().to_owned(); | |||||
| self.client | |||||
| .borrow_protocol_mut() | |||||
| .send_command_with_args("setprocname", name_bytes) | |||||
| .await | |||||
| } | |||||
| /// Changes the umask of the server process. | /// Changes the umask of the server process. | ||||
| fn set_umask(self, mask: u32) -> OneShotRequest<C>; | pub async fn set_umask(&mut self, mask: u32) -> io::Result<()> { | ||||
| let mut mask_bytes = BytesMut::with_capacity(mem::size_of_val(&mask)); | |||||
| mask_bytes.put_u32(mask); | |||||
| self.client | |||||
| .borrow_protocol_mut() | |||||
| .send_command_with_args("setumask2", mask_bytes) | |||||
| .await | |||||
| } | |||||
| /// Runs the specified Mercurial command with cHg extension. | /// Runs the specified Mercurial command with cHg extension. | ||||
| fn run_command_chg<H>( | pub async fn run_command_chg( | ||||
| self, | &mut self, | ||||
| handler: H, | handler: &mut impl SystemHandler, | ||||
| args: impl IntoIterator<Item = impl AsRef<OsStr>>, | args: impl IntoIterator<Item = impl AsRef<OsStr>>, | ||||
| ) -> ChgRunCommand<C, H> | ) -> io::Result<i32> { | ||||
| where | runcommand::run_command( | ||||
| H: SystemHandler; | self.client.borrow_protocol_mut(), | ||||
| handler, | |||||
| message::pack_args_os(args), | |||||
| ) | |||||
| .await | |||||
| } | |||||
| /// Validates if the server can run Mercurial commands with the expected | /// Validates if the server can run Mercurial commands with the expected | ||||
| /// configuration. | /// configuration. | ||||
| /// | /// | ||||
| /// The `args` should contain early command arguments such as `--config` | /// The `args` should contain early command arguments such as `--config` | ||||
| /// and `-R`. | /// and `-R`. | ||||
| /// | /// | ||||
| /// Client-side environment must be sent prior to this request, by | /// Client-side environment must be sent prior to this request, by | ||||
| /// `set_current_dir()` and `set_env_vars_os()`. | /// `set_current_dir()` and `set_env_vars_os()`. | ||||
| fn validate( | pub async fn validate( | ||||
| self, | &mut self, | ||||
| args: impl IntoIterator<Item = impl AsRef<OsStr>>, | args: impl IntoIterator<Item = impl AsRef<OsStr>>, | ||||
| ) -> OneShotQuery<C, fn(Bytes) -> io::Result<Vec<Instruction>>>; | ) -> io::Result<Vec<Instruction>> { | ||||
| } | let data = self | ||||
| .client | |||||
| impl<C> ChgClientExt<C> for Client<C> | .borrow_protocol_mut() | ||||
| where | .query_with_args("validate", message::pack_args_os(args)) | ||||
| C: Connection + AsRawFd, | .await?; | ||||
| { | message::parse_instructions(data) | ||||
| fn attach_io<I, O, E>(self, stdin: I, stdout: O, stderr: E) -> AttachIo<C, I, O, E> | |||||
| where | |||||
| I: AsRawFd, | |||||
| O: AsRawFd, | |||||
| E: AsRawFd, | |||||
| { | |||||
| AttachIo::with_client(self, stdin, stdout, Some(stderr)) | |||||
| } | |||||
| fn set_current_dir(self, dir: impl AsRef<Path>) -> OneShotRequest<C> { | |||||
| OneShotRequest::start_with_args(self, b"chdir", dir.as_ref().as_os_str().as_bytes()) | |||||
| } | |||||
| fn set_env_vars_os( | |||||
| self, | |||||
| vars: impl IntoIterator<Item = (impl AsRef<OsStr>, impl AsRef<OsStr>)>, | |||||
| ) -> OneShotRequest<C> { | |||||
| OneShotRequest::start_with_args(self, b"setenv", message::pack_env_vars_os(vars)) | |||||
| } | |||||
| fn set_process_name(self, name: impl AsRef<OsStr>) -> OneShotRequest<C> { | |||||
| OneShotRequest::start_with_args(self, b"setprocname", name.as_ref().as_bytes()) | |||||
| } | |||||
| fn set_umask(self, mask: u32) -> OneShotRequest<C> { | |||||
| let mut args = BytesMut::with_capacity(mem::size_of_val(&mask)); | |||||
| args.put_u32(mask); | |||||
| OneShotRequest::start_with_args(self, b"setumask2", args) | |||||
| } | |||||
| fn run_command_chg<H>( | |||||
| self, | |||||
| handler: H, | |||||
| args: impl IntoIterator<Item = impl AsRef<OsStr>>, | |||||
| ) -> ChgRunCommand<C, H> | |||||
| where | |||||
| H: SystemHandler, | |||||
| { | |||||
| ChgRunCommand::with_client(self, handler, message::pack_args_os(args)) | |||||
| } | |||||
| fn validate( | |||||
| self, | |||||
| args: impl IntoIterator<Item = impl AsRef<OsStr>>, | |||||
| ) -> OneShotQuery<C, fn(Bytes) -> io::Result<Vec<Instruction>>> { | |||||
| OneShotQuery::start_with_args( | |||||
| self, | |||||
| b"validate", | |||||
| message::pack_args_os(args), | |||||
| message::parse_instructions, | |||||
| ) | |||||
| } | } | ||||
| } | } | ||||
| // Copyright 2018 Yuya Nishihara <yuya@tcha.org> | // Copyright 2018 Yuya Nishihara <yuya@tcha.org> | ||||
| // | // | ||||
| // This software may be used and distributed according to the terms of the | // This software may be used and distributed according to the terms of the | ||||
| // GNU General Public License version 2 or any later version. | // GNU General Public License version 2 or any later version. | ||||
| mod attachio; | mod attachio; | ||||
| //mod clientext; | mod clientext; | ||||
| //pub mod locator; | //pub mod locator; | ||||
| pub mod message; | pub mod message; | ||||
| pub mod procutil; | pub mod procutil; | ||||
| mod runcommand; | mod runcommand; | ||||
| mod uihandler; | mod uihandler; | ||||
| //pub use clientext::ChgClientExt; | pub use clientext::ChgClient; | ||||
| pub use uihandler::{ChgUiHandler, SystemHandler}; | pub use uihandler::{ChgUiHandler, SystemHandler}; | ||||