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.
Automatic diff as part of commit; lint not applicable. |
Automatic diff as part of commit; unit tests not applicable. |
// 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}; |